Skip to content

Commit 14bb1b9

Browse files
committed
Merge pull request #202 from enwaytech:sr/reverse-backport-from-noetic
2 parents 6fe2d40 + 4b30703 commit 14bb1b9

8 files changed

Lines changed: 174 additions & 1 deletion

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: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@
2626
#include "rclcpp/rclcpp.hpp"
2727
#include "std_msgs/msg/string.hpp"
2828

29+
#include "tf2_ros/buffer.h"
2930
#include "tf2_ros/transform_broadcaster.hpp"
31+
#include "tf2_ros/transform_listener.h"
32+
#include <geometry_msgs/msg/pose_stamped.hpp>
3033
#include <geometry_msgs/msg/vector3_stamped.hpp>
3134
#include <message_filters/subscriber.hpp>
3235
#include <message_filters/sync_policies/approximate_time.hpp>
@@ -44,6 +47,7 @@ class ImuFilterMadgwickRos : public imu_filter::BaseNode
4447
typedef sensor_msgs::msg::Imu ImuMsg;
4548
typedef sensor_msgs::msg::MagneticField MagMsg;
4649
typedef geometry_msgs::msg::Vector3Stamped RpyVectorMsg;
50+
typedef geometry_msgs::msg::PoseStamped PoseMsg;
4751

4852
typedef message_filters::sync_policies::ApproximateTime<ImuMsg, MagMsg>
4953
SyncPolicy;
@@ -55,6 +59,9 @@ class ImuFilterMadgwickRos : public imu_filter::BaseNode
5559
IMU_FILTER_MADGWICK_CPP_PUBLIC
5660
explicit ImuFilterMadgwickRos(const rclcpp::NodeOptions& options);
5761

62+
// Reset the filter to the initial state.
63+
void reset();
64+
5865
// Callbacks are public so they can be called when used as a library
5966
void imuCallback(ImuMsg::ConstSharedPtr imu_msg_raw);
6067
void imuMagCallback(ImuMsg::ConstSharedPtr imu_msg_raw,
@@ -68,7 +75,10 @@ class ImuFilterMadgwickRos : public imu_filter::BaseNode
6875
rclcpp::Publisher<RpyVectorMsg>::SharedPtr rpy_filtered_debug_publisher_;
6976
rclcpp::Publisher<RpyVectorMsg>::SharedPtr rpy_raw_debug_publisher_;
7077
rclcpp::Publisher<ImuMsg>::SharedPtr imu_publisher_;
78+
rclcpp::Publisher<PoseMsg>::SharedPtr orientation_filtered_publisher_;
7179
tf2_ros::TransformBroadcaster tf_broadcaster_;
80+
tf2_ros::Buffer tf_buffer_;
81+
tf2_ros::TransformListener tf_listener_;
7282

7383
rclcpp::TimerBase::SharedPtr check_topics_timer_;
7484

@@ -90,11 +100,13 @@ class ImuFilterMadgwickRos : public imu_filter::BaseNode
90100
geometry_msgs::msg::Vector3 mag_bias_;
91101
double orientation_variance_;
92102
double yaw_offset_total_;
103+
rclcpp::Duration time_jump_threshold_duration_{0, 0};
93104

94105
// **** state variables
95106
std::mutex mutex_;
96107
bool initialized_;
97108
rclcpp::Time last_time_;
109+
rclcpp::Time last_ros_time_;
98110
tf2::Quaternion yaw_offsets_;
99111

100112
// **** filter implementation
@@ -103,6 +115,7 @@ class ImuFilterMadgwickRos : public imu_filter::BaseNode
103115
// **** member functions
104116
void publishFilteredMsg(ImuMsg::ConstSharedPtr imu_msg_raw);
105117
void publishTransform(ImuMsg::ConstSharedPtr imu_msg_raw);
118+
void publishOrientationFiltered(const ImuMsg& imu_msg);
106119

107120
void publishRawMsg(const rclcpp::Time& t, float roll, float pitch,
108121
float yaw);
@@ -112,4 +125,7 @@ class ImuFilterMadgwickRos : public imu_filter::BaseNode
112125
void checkTopicsTimerCallback();
113126

114127
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();
115131
};

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: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ using namespace std::placeholders;
3737
ImuFilterMadgwickRos::ImuFilterMadgwickRos(const rclcpp::NodeOptions &options)
3838
: BaseNode("imu_filter_madgwick", options),
3939
tf_broadcaster_(*this),
40+
tf_buffer_(this->get_clock()),
41+
tf_listener_(tf_buffer_),
4042
initialized_(false)
4143
{
4244
RCLCPP_INFO(get_logger(), "Starting ImuFilter");
@@ -61,6 +63,12 @@ ImuFilterMadgwickRos::ImuFilterMadgwickRos(const rclcpp::NodeOptions &options)
6163
declare_parameter("publish_debug_topics", false, descriptor);
6264
get_parameter("publish_debug_topics", publish_debug_topics_);
6365

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+
6472
double yaw_offset = 0.0;
6573
declare_parameter("yaw_offset", 0.0, descriptor);
6674
get_parameter("yaw_offset", yaw_offset);
@@ -128,6 +136,8 @@ ImuFilterMadgwickRos::ImuFilterMadgwickRos(const rclcpp::NodeOptions &options)
128136
"The gravity vector is kept in the IMU message.");
129137
}
130138

139+
last_ros_time_ = this->get_clock()->now();
140+
131141
// **** define reconfigurable parameters.
132142
double gain;
133143
floating_point_range float_range = {0.0, 1.0, 0};
@@ -151,7 +161,7 @@ ImuFilterMadgwickRos::ImuFilterMadgwickRos(const rclcpp::NodeOptions &options)
151161
add_parameter("mag_bias_z", rclcpp::ParameterValue(0.0), float_range,
152162
"Magnetometer bias (hard iron correction), z component.");
153163
double orientation_stddev;
154-
float_range = {0.0, 1.0, 0};
164+
float_range = {0.0, 100.0, 0};
155165
add_parameter("orientation_stddev", rclcpp::ParameterValue(0.0),
156166
float_range,
157167
"Standard deviation of the orientation estimate.");
@@ -191,6 +201,10 @@ ImuFilterMadgwickRos::ImuFilterMadgwickRos(const rclcpp::NodeOptions &options)
191201
rpy_raw_debug_publisher_ =
192202
create_publisher<geometry_msgs::msg::Vector3Stamped>("imu/rpy/raw",
193203
5);
204+
205+
orientation_filtered_publisher_ =
206+
create_publisher<geometry_msgs::msg::PoseStamped>(
207+
"imu/orientation_filtered", 5);
194208
}
195209

196210
// **** register subscribers
@@ -220,6 +234,8 @@ ImuFilterMadgwickRos::ImuFilterMadgwickRos(const rclcpp::NodeOptions &options)
220234

221235
void ImuFilterMadgwickRos::imuCallback(ImuMsg::ConstSharedPtr imu_msg_raw)
222236
{
237+
checkTimeJump();
238+
223239
std::lock_guard<std::mutex> lock(mutex_);
224240

225241
const geometry_msgs::msg::Vector3 &ang_vel = imu_msg_raw->angular_velocity;
@@ -285,6 +301,8 @@ void ImuFilterMadgwickRos::imuCallback(ImuMsg::ConstSharedPtr imu_msg_raw)
285301
void ImuFilterMadgwickRos::imuMagCallback(ImuMsg::ConstSharedPtr imu_msg_raw,
286302
MagMsg::ConstSharedPtr mag_msg)
287303
{
304+
checkTimeJump();
305+
288306
std::lock_guard<std::mutex> lock(mutex_);
289307

290308
const geometry_msgs::msg::Vector3 &ang_vel = imu_msg_raw->angular_velocity;
@@ -480,9 +498,40 @@ void ImuFilterMadgwickRos::publishFilteredMsg(
480498

481499
rpy.header = imu_msg_raw->header;
482500
rpy_filtered_debug_publisher_->publish(rpy);
501+
502+
publishOrientationFiltered(imu_msg);
483503
}
484504
}
485505

506+
void ImuFilterMadgwickRos::publishOrientationFiltered(const ImuMsg &imu_msg)
507+
{
508+
geometry_msgs::msg::PoseStamped pose;
509+
pose.header.stamp = imu_msg.header.stamp;
510+
pose.header.frame_id = fixed_frame_;
511+
pose.pose.orientation = imu_msg.orientation;
512+
513+
// get the current transform from the fixed frame to the imu frame
514+
geometry_msgs::msg::TransformStamped transform;
515+
try
516+
{
517+
transform = tf_buffer_.lookupTransform(
518+
fixed_frame_, imu_msg.header.frame_id, imu_msg.header.stamp,
519+
rclcpp::Duration::from_seconds(0.1));
520+
} catch (tf2::TransformException &ex)
521+
{
522+
RCLCPP_WARN(
523+
this->get_logger(), "Could not get transform from %s to %s: %s",
524+
fixed_frame_.c_str(), imu_msg.header.frame_id.c_str(), ex.what());
525+
return;
526+
}
527+
528+
pose.pose.position.x = transform.transform.translation.x;
529+
pose.pose.position.y = transform.transform.translation.y;
530+
pose.pose.position.z = transform.transform.translation.z;
531+
532+
orientation_filtered_publisher_->publish(pose);
533+
}
534+
486535
void ImuFilterMadgwickRos::publishRawMsg(const rclcpp::Time &t, float roll,
487536
float pitch, float yaw)
488537
{
@@ -545,6 +594,40 @@ void ImuFilterMadgwickRos::checkTopicsTimerCallback()
545594
<< "...");
546595
}
547596

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+
548631
#include "rclcpp_components/register_node_macro.hpp"
549632

550633
RCLCPP_COMPONENTS_REGISTER_NODE(ImuFilterMadgwickRos)

0 commit comments

Comments
 (0)