Skip to content

Commit bffaf15

Browse files
fix(ekf_localizer): add imu option for roll pitch and height estimation
Signed-off-by: Melike Tanrıkulu <melike@leodrive.ai>
1 parent 26e87ea commit bffaf15

File tree

5 files changed

+158
-15
lines changed

5 files changed

+158
-15
lines changed

localization/ekf_localizer/config/ekf_localizer.param.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,4 @@
4949
# for velocity measurement limitation (Set 0.0 if you want to ignore)
5050
threshold_observable_velocity_mps: 0.0 # [m/s]
5151
pose_frame_id: "map"
52+
use_imu: false

localization/ekf_localizer/include/ekf_localizer/ekf_localizer.hpp

+34-1
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,19 @@
3333
#include <geometry_msgs/msg/twist_stamped.hpp>
3434
#include <geometry_msgs/msg/twist_with_covariance_stamped.hpp>
3535
#include <nav_msgs/msg/odometry.hpp>
36+
#include <sensor_msgs/msg/imu.hpp>
3637
#include <std_srvs/srv/set_bool.hpp>
3738
#include <tier4_debug_msgs/msg/float64_multi_array_stamped.hpp>
3839
#include <tier4_debug_msgs/msg/float64_stamped.hpp>
3940

4041
#include <tf2/LinearMath/Quaternion.h>
4142
#include <tf2/utils.h>
43+
#include <tf2_ros/buffer.h>
4244
#include <tf2_ros/transform_broadcaster.h>
4345
#include <tf2_ros/transform_listener.h>
4446

4547
#include <chrono>
48+
#include <deque>
4649
#include <iostream>
4750
#include <memory>
4851
#include <queue>
@@ -129,6 +132,8 @@ class EKFLocalizer : public rclcpp::Node
129132
//!< @brief measurement twist with covariance subscriber
130133
rclcpp::Subscription<geometry_msgs::msg::TwistWithCovarianceStamped>::SharedPtr
131134
sub_twist_with_cov_;
135+
//!< @brief imu subscriber
136+
rclcpp::Subscription<sensor_msgs::msg::Imu>::SharedPtr sub_imu_;
132137
//!< @brief time for ekf calculation callback
133138
rclcpp::TimerBase::SharedPtr timer_control_;
134139
//!< @brief last predict time
@@ -154,13 +159,38 @@ class EKFLocalizer : public rclcpp::Node
154159

155160
double ekf_dt_;
156161

162+
//////////////////////////////////////////////////////////////////////////////
163+
157164
/* process noise variance for discrete model */
158165
double proc_cov_yaw_d_; //!< @brief discrete yaw process noise
159166
double proc_cov_vx_d_; //!< @brief discrete process noise in d_vx=0
160167
double proc_cov_wz_d_; //!< @brief discrete process noise in d_wz=0
161168

162169
bool is_activated_;
163170

171+
double imu_dt_;
172+
bool start = 0;
173+
rclcpp::Time last_imu_time_ = rclcpp::Time(0, 0);
174+
std::deque<sensor_msgs::msg::Imu> imu_msg_deque_;
175+
sensor_msgs::msg::Imu find_closest_imu_msg(const rclcpp::Time & current_time);
176+
177+
builtin_interfaces::msg::Time pose_time_;
178+
179+
std::shared_ptr<tf2_ros::Buffer> tf_buffer_;
180+
std::shared_ptr<tf2_ros::TransformListener> tf_listener_;
181+
struct RollPitchHeightStruct
182+
{
183+
double roll;
184+
double pitch;
185+
double z;
186+
};
187+
188+
RollPitchHeightStruct get_roll_pitch_height(const rclcpp::Time current_time);
189+
190+
rclcpp::Time prev_time_;
191+
double imu_counter = 0;
192+
//////////////////////////////////////////////////////////////////////////////
193+
164194
EKFDiagnosticInfo pose_diag_info_;
165195
EKFDiagnosticInfo twist_diag_info_;
166196

@@ -187,7 +217,10 @@ class EKFLocalizer : public rclcpp::Node
187217
*/
188218
void callback_twist_with_covariance(
189219
geometry_msgs::msg::TwistWithCovarianceStamped::SharedPtr msg);
190-
220+
/**
221+
* @brief get imu data
222+
*/
223+
void callback_imu(sensor_msgs::msg::Imu::SharedPtr msg);
191224
/**
192225
* @brief set initial_pose to current EKF pose
193226
*/

localization/ekf_localizer/include/ekf_localizer/hyper_parameters.hpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ class HyperParameters
6565
warn_ellipse_size_lateral_direction(
6666
node->declare_parameter<double>("diagnostics.warn_ellipse_size_lateral_direction")),
6767
threshold_observable_velocity_mps(
68-
node->declare_parameter<double>("misc.threshold_observable_velocity_mps"))
68+
node->declare_parameter<double>("misc.threshold_observable_velocity_mps")),
69+
use_imu(node->declare_parameter<bool>("misc.use_imu"))
6970
{
7071
}
7172

@@ -100,6 +101,7 @@ class HyperParameters
100101
double warn_ellipse_size_lateral_direction;
101102

102103
const double threshold_observable_velocity_mps;
104+
const bool use_imu;
103105
};
104106

105107
#endif // EKF_LOCALIZER__HYPER_PARAMETERS_HPP_

localization/ekf_localizer/schema/sub/misc.sub_schema.json

+6-1
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,14 @@
1414
"type": "string",
1515
"description": "Parent frame_id of EKF output pose",
1616
"default": "map"
17+
},
18+
"use_imu": {
19+
"type": "boolean",
20+
"description": "Use IMU data instead of 1D Filter for roll,pitch, position Z estimation",
21+
"default": false
1722
}
1823
},
19-
"required": ["threshold_observable_velocity_mps", "pose_frame_id"],
24+
"required": ["threshold_observable_velocity_mps", "pose_frame_id", "use_imu"],
2025
"additionalProperties": false
2126
}
2227
}

localization/ekf_localizer/src/ekf_localizer.cpp

+114-12
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,16 @@
1818
#include "ekf_localizer/string.hpp"
1919
#include "ekf_localizer/warning_message.hpp"
2020
#include "localization_util/covariance_ellipse.hpp"
21+
#include "tf2/LinearMath/Quaternion.h"
2122

2223
#include <autoware/universe_utils/geometry/geometry.hpp>
2324
#include <autoware/universe_utils/math/unit_conversion.hpp>
2425
#include <autoware/universe_utils/ros/msg_covariance.hpp>
2526
#include <rclcpp/duration.hpp>
2627
#include <rclcpp/logging.hpp>
2728

29+
#include "tf2_geometry_msgs/tf2_geometry_msgs/tf2_geometry_msgs.hpp"
30+
2831
#include <fmt/core.h>
2932

3033
#include <algorithm>
@@ -87,6 +90,12 @@ EKFLocalizer::EKFLocalizer(const rclcpp::NodeOptions & node_options)
8790
sub_twist_with_cov_ = create_subscription<geometry_msgs::msg::TwistWithCovarianceStamped>(
8891
"in_twist_with_covariance", 1,
8992
std::bind(&EKFLocalizer::callback_twist_with_covariance, this, _1));
93+
if (params_.use_imu) {
94+
sub_imu_ = create_subscription<sensor_msgs::msg::Imu>(
95+
"/sensing/gnss/sbg/ros/imu/data", 1, std::bind(&EKFLocalizer::callback_imu, this, _1));
96+
tf_buffer_ = std::make_shared<tf2_ros::Buffer>(this->get_clock());
97+
tf_listener_ = std::make_shared<tf2_ros::TransformListener>(*tf_buffer_);
98+
}
9099
service_trigger_node_ = create_service<std_srvs::srv::SetBool>(
91100
"trigger_node_srv",
92101
std::bind(
@@ -102,6 +111,8 @@ EKFLocalizer::EKFLocalizer(const rclcpp::NodeOptions & node_options)
102111
z_filter_.set_proc_dev(params_.z_filter_proc_dev);
103112
roll_filter_.set_proc_dev(params_.roll_filter_proc_dev);
104113
pitch_filter_.set_proc_dev(params_.pitch_filter_proc_dev);
114+
115+
std::cout << "*********************** use_imu: " << params_.use_imu << std::endl;
105116
}
106117

107118
/*
@@ -230,13 +241,12 @@ void EKFLocalizer::timer_callback()
230241
}
231242
twist_diag_info_.no_update_count = twist_is_updated ? 0 : (twist_diag_info_.no_update_count + 1);
232243

233-
const double z = z_filter_.get_x();
234-
const double roll = roll_filter_.get_x();
235-
const double pitch = pitch_filter_.get_x();
236-
const geometry_msgs::msg::PoseStamped current_ekf_pose =
237-
ekf_module_->get_current_pose(current_time, z, roll, pitch, false);
238-
const geometry_msgs::msg::PoseStamped current_biased_ekf_pose =
239-
ekf_module_->get_current_pose(current_time, z, roll, pitch, true);
244+
RollPitchHeightStruct roll_pitch_height = get_roll_pitch_height(current_time);
245+
246+
const geometry_msgs::msg::PoseStamped current_ekf_pose = ekf_module_->get_current_pose(
247+
current_time, roll_pitch_height.z, roll_pitch_height.roll, roll_pitch_height.pitch, false);
248+
const geometry_msgs::msg::PoseStamped current_biased_ekf_pose = ekf_module_->get_current_pose(
249+
current_time, roll_pitch_height.z, roll_pitch_height.roll, roll_pitch_height.pitch, true);
240250
const geometry_msgs::msg::TwistStamped current_ekf_twist =
241251
ekf_module_->get_current_twist(current_time);
242252

@@ -245,6 +255,53 @@ void EKFLocalizer::timer_callback()
245255
publish_diagnostics(current_ekf_pose, current_time);
246256
}
247257

258+
/*
259+
* find_closest_imu_msg
260+
*/
261+
sensor_msgs::msg::Imu EKFLocalizer::find_closest_imu_msg(const rclcpp::Time & current_time)
262+
{
263+
sensor_msgs::msg::Imu closest_imu_msg;
264+
uint64_t min_time_diff = std::numeric_limits<uint64_t>::max();
265+
const int64_t pose_time_ns = current_time.nanoseconds();
266+
267+
for (const auto & imu_msg : imu_msg_deque_) {
268+
const int64_t imu_time_ns = imu_msg.header.stamp.sec * 1e9 + imu_msg.header.stamp.nanosec;
269+
uint64_t time_diff = std::abs(pose_time_ns - imu_time_ns);
270+
if (time_diff < min_time_diff) {
271+
min_time_diff = time_diff;
272+
closest_imu_msg = imu_msg;
273+
}
274+
}
275+
return closest_imu_msg;
276+
}
277+
278+
/*
279+
* get_roll_pitch_height
280+
*/
281+
EKFLocalizer::RollPitchHeightStruct EKFLocalizer::get_roll_pitch_height(
282+
const rclcpp::Time current_time)
283+
{
284+
RollPitchHeightStruct roll_pitch_height;
285+
286+
if (params_.use_imu && !imu_msg_deque_.empty() && imu_dt_ > 0.0) { //???
287+
sensor_msgs::msg::Imu new_imu_msg = find_closest_imu_msg(current_time);
288+
roll_pitch_height.z =
289+
z_filter_.get_x() + new_imu_msg.linear_acceleration.z * imu_dt_ * imu_dt_ / 2.0;
290+
const auto rpy = autoware::universe_utils::getRPY(new_imu_msg.orientation);
291+
roll_pitch_height.roll = rpy.x;
292+
roll_pitch_height.pitch = rpy.y;
293+
} else {
294+
if (params_.use_imu && imu_msg_deque_.empty()) {
295+
RCLCPP_WARN(this->get_logger(), "IMU data is expected but the deque is empty.");
296+
}
297+
roll_pitch_height.z = z_filter_.get_x();
298+
roll_pitch_height.roll = roll_filter_.get_x();
299+
roll_pitch_height.pitch = pitch_filter_.get_x();
300+
}
301+
302+
return roll_pitch_height;
303+
}
304+
248305
/*
249306
* timer_tf_callback
250307
*/
@@ -258,15 +315,15 @@ void EKFLocalizer::timer_tf_callback()
258315
return;
259316
}
260317

261-
const double z = z_filter_.get_x();
262-
const double roll = roll_filter_.get_x();
263-
const double pitch = pitch_filter_.get_x();
264-
265318
const rclcpp::Time current_time = this->now();
266319

320+
RollPitchHeightStruct roll_pitch_height = get_roll_pitch_height(current_time);
321+
267322
geometry_msgs::msg::TransformStamped transform_stamped;
268323
transform_stamped = autoware::universe_utils::pose2transform(
269-
ekf_module_->get_current_pose(current_time, z, roll, pitch, false), "base_link");
324+
ekf_module_->get_current_pose(
325+
current_time, roll_pitch_height.z, roll_pitch_height.roll, roll_pitch_height.pitch, false),
326+
"base_link");
270327
transform_stamped.header.stamp = current_time;
271328
tf_br_->sendTransform(transform_stamped);
272329
}
@@ -340,6 +397,51 @@ void EKFLocalizer::callback_twist_with_covariance(
340397
twist_queue_.push(msg);
341398
}
342399

400+
/*
401+
* callback_imu
402+
*/
403+
void EKFLocalizer::callback_imu(sensor_msgs::msg::Imu::SharedPtr msg)
404+
{
405+
sensor_msgs::msg::Imu imu_data = *msg;
406+
407+
geometry_msgs::msg::TransformStamped imu_to_base_link_transform;
408+
try {
409+
imu_to_base_link_transform =
410+
tf_buffer_->lookupTransform("base_link", imu_data.header.frame_id, tf2::TimePointZero);
411+
} catch (tf2::TransformException & ex) {
412+
RCLCPP_WARN(this->get_logger(), "Transform Error: %s", ex.what());
413+
return;
414+
}
415+
416+
tf2::Quaternion imu_quat;
417+
tf2::fromMsg(imu_data.orientation, imu_quat);
418+
419+
tf2::Quaternion transformed_quat = tf2::Transform(tf2::Quaternion(
420+
imu_to_base_link_transform.transform.rotation.x,
421+
imu_to_base_link_transform.transform.rotation.y,
422+
imu_to_base_link_transform.transform.rotation.z,
423+
imu_to_base_link_transform.transform.rotation.w)) *
424+
imu_quat;
425+
426+
geometry_msgs::msg::Quaternion new_orientation = tf2::toMsg(transformed_quat);
427+
428+
sensor_msgs::msg::Imu new_imu_msg;
429+
new_imu_msg = imu_data;
430+
new_imu_msg.orientation = new_orientation;
431+
imu_msg_deque_.push_back(new_imu_msg);
432+
433+
while (imu_msg_deque_.size() > 15) {
434+
imu_msg_deque_.pop_front();
435+
}
436+
if (start == 1) {
437+
imu_dt_ = std::abs((last_imu_time_ - msg->header.stamp).seconds());
438+
start = 0;
439+
}
440+
start = 1;
441+
442+
last_imu_time_ = msg->header.stamp;
443+
}
444+
343445
/*
344446
* publish_estimate_result
345447
*/

0 commit comments

Comments
 (0)