Skip to content

Commit 6fbdce5

Browse files
feat(distortion_corrector): use gyroscope for correcting LiDAR distortion (autowarefoundation#1120)
* first commit Signed-off-by: kminoda <koji.m.minoda@gmail.com> * ci(pre-commit): autofix * check if angular_velocity_queue_ is empty or not Signed-off-by: kminoda <koji.m.minoda@gmail.com> * move vehicle velocity converter to sensing Signed-off-by: kminoda <koji.m.minoda@gmail.com> * ci(pre-commit): autofix * fix Signed-off-by: kminoda <koji.m.minoda@gmail.com> * ci(pre-commit): autofix * reflected reviews Signed-off-by: kminoda <koji.m.minoda@gmail.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 458a32d commit 6fbdce5

File tree

12 files changed

+118
-53
lines changed

12 files changed

+118
-53
lines changed

launch/tier4_localization_launch/launch/twist_estimator/twist_estimator.launch.xml

+1-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
<?xml version="1.0"?>
22
<launch>
3-
<include file="$(find-pkg-share vehicle_velocity_converter)/launch/vehicle_velocity_converter.launch.xml">
4-
<arg name="input_vehicle_velocity_topic" value="/vehicle/status/velocity_status"/>
5-
<arg name="output_twist_with_covariance" value="/localization/twist_estimator/vehicle_velocity_converter/twist_with_covariance"/>
6-
</include>
73
<include file="$(find-pkg-share gyro_odometer)/launch/gyro_odometer.launch.xml">
8-
<arg name="input_vehicle_twist_with_covariance_topic" value="/localization/twist_estimator/vehicle_velocity_converter/twist_with_covariance"/>
4+
<arg name="input_vehicle_twist_with_covariance_topic" value="/sensing/vehicle_velocity_converter/twist_with_covariance"/>
95
<arg name="output_twist_with_covariance_topic" value="/localization/twist_estimator/twist_with_covariance"/>
106
<arg name="output_twist_with_covariance_raw_topic" value="/localization/twist_estimator/twist_with_covariance_raw"/>
117
</include>

sensing/pointcloud_preprocessor/docs/distortion-corrector.md

+9-7
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,11 @@ $ ExactPointTime = TimeStamp + TimeOffset $
2323

2424
### Input
2525

26-
| Name | Type | Description |
27-
| ------------------------- | ------------------------------------------------- | ---------------- |
28-
| `~/input/points` | `sensor_msgs::msg::PointCloud2` | reference points |
29-
| `~/input/velocity_report` | `autoware_auto_vehicle_msgs::msg::VelocityReport` | vehicle velocity |
26+
| Name | Type | Description |
27+
| ---------------- | ------------------------------------------------ | ---------------- |
28+
| `~/input/points` | `sensor_msgs::msg::PointCloud2` | reference points |
29+
| `~/input/twist` | `geometry_msgs::msg::TwistWithCovarianceStamped` | twist |
30+
| `~/input/imu` | `sensor_msgs::msg::Imu` | imu data |
3031

3132
### Output
3233

@@ -38,8 +39,9 @@ $ ExactPointTime = TimeStamp + TimeOffset $
3839

3940
### Core Parameters
4041

41-
| Name | Type | Default Value | Description |
42-
| ---------------------- | ------ | ------------- | --------------------- |
43-
| `timestamp_field_name` | string | "time_stamp" | time stamp field name |
42+
| Name | Type | Default Value | Description |
43+
| ---------------------- | ------ | ------------- | ----------------------------------------------------------- |
44+
| `timestamp_field_name` | string | "time_stamp" | time stamp field name |
45+
| `use_imu` | bool | true | use gyroscope for yaw rate if true, else use vehicle status |
4446

4547
## Assumptions / Known limits

sensing/pointcloud_preprocessor/include/pointcloud_preprocessor/distortion_corrector/distortion_corrector.hpp

+12-8
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717

1818
#include <rclcpp/rclcpp.hpp>
1919

20-
#include <autoware_auto_vehicle_msgs/msg/velocity_report.hpp>
20+
#include <geometry_msgs/msg/twist_stamped.hpp>
21+
#include <geometry_msgs/msg/twist_with_covariance_stamped.hpp>
22+
#include <sensor_msgs/msg/imu.hpp>
2123
#include <sensor_msgs/msg/point_cloud2.hpp>
2224
#include <sensor_msgs/point_cloud2_iterator.hpp>
2325

@@ -43,7 +45,6 @@
4345

4446
namespace pointcloud_preprocessor
4547
{
46-
using autoware_auto_vehicle_msgs::msg::VelocityReport;
4748
using rcl_interfaces::msg::SetParametersResult;
4849
using sensor_msgs::msg::PointCloud2;
4950

@@ -54,17 +55,18 @@ class DistortionCorrectorComponent : public rclcpp::Node
5455

5556
private:
5657
void onPointCloud(PointCloud2::UniquePtr points_msg);
57-
void onVelocityReport(const VelocityReport::ConstSharedPtr velocity_report_msg);
58+
void onTwistWithCovarianceStamped(
59+
const geometry_msgs::msg::TwistWithCovarianceStamped::ConstSharedPtr twist_msg);
60+
void onImu(const sensor_msgs::msg::Imu::ConstSharedPtr imu_msg);
5861
bool getTransform(
5962
const std::string & target_frame, const std::string & source_frame,
6063
tf2::Transform * tf2_transform_ptr);
6164

62-
bool undistortPointCloud(
63-
const std::deque<VelocityReport> & velocity_report_queue,
64-
const tf2::Transform & tf2_base_link_to_sensor, PointCloud2 & points);
65+
bool undistortPointCloud(const tf2::Transform & tf2_base_link_to_sensor, PointCloud2 & points);
6566

6667
rclcpp::Subscription<PointCloud2>::SharedPtr input_points_sub_;
67-
rclcpp::Subscription<VelocityReport>::SharedPtr velocity_report_sub_;
68+
rclcpp::Subscription<sensor_msgs::msg::Imu>::SharedPtr imu_sub_;
69+
rclcpp::Subscription<geometry_msgs::msg::TwistWithCovarianceStamped>::SharedPtr twist_sub_;
6870
rclcpp::Publisher<PointCloud2>::SharedPtr undistorted_points_pub_;
6971

7072
std::unique_ptr<tier4_autoware_utils::StopWatch<std::chrono::milliseconds>> stop_watch_ptr_;
@@ -73,10 +75,12 @@ class DistortionCorrectorComponent : public rclcpp::Node
7375
tf2_ros::Buffer tf2_buffer_{get_clock()};
7476
tf2_ros::TransformListener tf2_listener_{tf2_buffer_};
7577

76-
std::deque<autoware_auto_vehicle_msgs::msg::VelocityReport> velocity_report_queue_;
78+
std::deque<geometry_msgs::msg::TwistStamped> twist_queue_;
79+
std::deque<geometry_msgs::msg::Vector3Stamped> angular_velocity_queue_;
7780

7881
std::string base_link_frame_ = "base_link";
7982
std::string time_stamp_field_name_;
83+
bool use_imu_;
8084
};
8185

8286
} // namespace pointcloud_preprocessor

sensing/pointcloud_preprocessor/src/distortion_corrector/distortion_corrector.cpp

+96-33
Original file line numberDiff line numberDiff line change
@@ -36,35 +36,76 @@ DistortionCorrectorComponent::DistortionCorrectorComponent(const rclcpp::NodeOpt
3636

3737
// Parameter
3838
time_stamp_field_name_ = declare_parameter("time_stamp_field_name", "time_stamp");
39+
use_imu_ = declare_parameter("use_imu", true);
3940

4041
// Publisher
4142
undistorted_points_pub_ =
4243
this->create_publisher<PointCloud2>("~/output/pointcloud", rclcpp::SensorDataQoS());
4344

4445
// Subscriber
45-
velocity_report_sub_ = this->create_subscription<VelocityReport>(
46-
"~/input/velocity_report", 10,
47-
std::bind(&DistortionCorrectorComponent::onVelocityReport, this, std::placeholders::_1));
46+
twist_sub_ = this->create_subscription<geometry_msgs::msg::TwistWithCovarianceStamped>(
47+
"~/input/twist", 10,
48+
std::bind(
49+
&DistortionCorrectorComponent::onTwistWithCovarianceStamped, this, std::placeholders::_1));
50+
imu_sub_ = this->create_subscription<sensor_msgs::msg::Imu>(
51+
"~/input/imu", 10,
52+
std::bind(&DistortionCorrectorComponent::onImu, this, std::placeholders::_1));
4853
input_points_sub_ = this->create_subscription<PointCloud2>(
4954
"~/input/pointcloud", rclcpp::SensorDataQoS(),
5055
std::bind(&DistortionCorrectorComponent::onPointCloud, this, std::placeholders::_1));
5156
}
5257

53-
void DistortionCorrectorComponent::onVelocityReport(
54-
const VelocityReport::ConstSharedPtr velocity_report_msg)
58+
void DistortionCorrectorComponent::onTwistWithCovarianceStamped(
59+
const geometry_msgs::msg::TwistWithCovarianceStamped::ConstSharedPtr twist_msg)
5560
{
56-
velocity_report_queue_.push_back(*velocity_report_msg);
61+
geometry_msgs::msg::TwistStamped msg;
62+
msg.header = twist_msg->header;
63+
msg.twist = twist_msg->twist.twist;
64+
twist_queue_.push_back(msg);
5765

58-
while (!velocity_report_queue_.empty()) {
66+
while (!twist_queue_.empty()) {
67+
// for replay rosbag
68+
if (rclcpp::Time(twist_queue_.front().header.stamp) > rclcpp::Time(twist_msg->header.stamp)) {
69+
twist_queue_.pop_front();
70+
} else if ( // NOLINT
71+
rclcpp::Time(twist_queue_.front().header.stamp) <
72+
rclcpp::Time(twist_msg->header.stamp) - rclcpp::Duration::from_seconds(1.0)) {
73+
twist_queue_.pop_front();
74+
}
75+
break;
76+
}
77+
}
78+
79+
void DistortionCorrectorComponent::onImu(const sensor_msgs::msg::Imu::ConstSharedPtr imu_msg)
80+
{
81+
if (!use_imu_) {
82+
return;
83+
}
84+
85+
tf2::Transform tf2_imu_link_to_base_link{};
86+
getTransform(base_link_frame_, imu_msg->header.frame_id, &tf2_imu_link_to_base_link);
87+
geometry_msgs::msg::TransformStamped::SharedPtr tf_base2imu_ptr =
88+
std::make_shared<geometry_msgs::msg::TransformStamped>();
89+
tf_base2imu_ptr->transform.rotation = tf2::toMsg(tf2_imu_link_to_base_link.getRotation());
90+
91+
geometry_msgs::msg::Vector3Stamped angular_velocity;
92+
angular_velocity.vector = imu_msg->angular_velocity;
93+
94+
geometry_msgs::msg::Vector3Stamped transformed_angular_velocity;
95+
tf2::doTransform(angular_velocity, transformed_angular_velocity, *tf_base2imu_ptr);
96+
transformed_angular_velocity.header = imu_msg->header;
97+
angular_velocity_queue_.push_back(transformed_angular_velocity);
98+
99+
while (!angular_velocity_queue_.empty()) {
59100
// for replay rosbag
60101
if (
61-
rclcpp::Time(velocity_report_queue_.front().header.stamp) >
62-
rclcpp::Time(velocity_report_msg->header.stamp)) {
63-
velocity_report_queue_.pop_front();
102+
rclcpp::Time(angular_velocity_queue_.front().header.stamp) >
103+
rclcpp::Time(imu_msg->header.stamp)) {
104+
angular_velocity_queue_.pop_front();
64105
} else if ( // NOLINT
65-
rclcpp::Time(velocity_report_queue_.front().header.stamp) <
66-
rclcpp::Time(velocity_report_msg->header.stamp) - rclcpp::Duration::from_seconds(1.0)) {
67-
velocity_report_queue_.pop_front();
106+
rclcpp::Time(angular_velocity_queue_.front().header.stamp) <
107+
rclcpp::Time(imu_msg->header.stamp) - rclcpp::Duration::from_seconds(1.0)) {
108+
angular_velocity_queue_.pop_front();
68109
}
69110
break;
70111
}
@@ -83,11 +124,10 @@ void DistortionCorrectorComponent::onPointCloud(PointCloud2::UniquePtr points_ms
83124
tf2::Transform tf2_base_link_to_sensor{};
84125
getTransform(points_msg->header.frame_id, base_link_frame_, &tf2_base_link_to_sensor);
85126

86-
undistortPointCloud(velocity_report_queue_, tf2_base_link_to_sensor, *points_msg);
127+
undistortPointCloud(tf2_base_link_to_sensor, *points_msg);
128+
129+
undistorted_points_pub_->publish(std::move(points_msg));
87130

88-
if (points_sub_count > 0) {
89-
undistorted_points_pub_->publish(std::move(points_msg));
90-
}
91131
// add processing time for debug
92132
if (debug_publisher_) {
93133
const double cyclic_time_ms = stop_watch_ptr_->toc("cyclic_time", true);
@@ -126,13 +166,12 @@ bool DistortionCorrectorComponent::getTransform(
126166
}
127167

128168
bool DistortionCorrectorComponent::undistortPointCloud(
129-
const std::deque<VelocityReport> & velocity_report_queue_,
130169
const tf2::Transform & tf2_base_link_to_sensor, PointCloud2 & points)
131170
{
132-
if (points.data.empty() || velocity_report_queue_.empty()) {
171+
if (points.data.empty() || twist_queue_.empty()) {
133172
RCLCPP_WARN_STREAM_THROTTLE(
134173
get_logger(), *get_clock(), 10000 /* ms */,
135-
"input_pointcloud->points or velocity_report_queue_ is empty.");
174+
"input_pointcloud->points or twist_queue_ is empty.");
136175
return false;
137176
}
138177

@@ -159,34 +198,58 @@ bool DistortionCorrectorComponent::undistortPointCloud(
159198
double prev_time_stamp_sec{*it_time_stamp};
160199
const double first_point_time_stamp_sec{*it_time_stamp};
161200

162-
auto velocity_report_it = std::lower_bound(
163-
std::begin(velocity_report_queue_), std::end(velocity_report_queue_),
164-
first_point_time_stamp_sec, [](const VelocityReport & x, const double t) {
201+
auto twist_it = std::lower_bound(
202+
std::begin(twist_queue_), std::end(twist_queue_), first_point_time_stamp_sec,
203+
[](const geometry_msgs::msg::TwistStamped & x, const double t) {
165204
return rclcpp::Time(x.header.stamp).seconds() < t;
166205
});
167-
velocity_report_it = velocity_report_it == std::end(velocity_report_queue_)
168-
? std::end(velocity_report_queue_) - 1
169-
: velocity_report_it;
206+
twist_it = twist_it == std::end(twist_queue_) ? std::end(twist_queue_) - 1 : twist_it;
207+
208+
decltype(angular_velocity_queue_)::iterator imu_it;
209+
if (use_imu_ && !angular_velocity_queue_.empty()) {
210+
imu_it = std::lower_bound(
211+
std::begin(angular_velocity_queue_), std::end(angular_velocity_queue_),
212+
first_point_time_stamp_sec, [](const geometry_msgs::msg::Vector3Stamped & x, const double t) {
213+
return rclcpp::Time(x.header.stamp).seconds() < t;
214+
});
215+
imu_it =
216+
imu_it == std::end(angular_velocity_queue_) ? std::end(angular_velocity_queue_) - 1 : imu_it;
217+
}
170218

171219
const tf2::Transform tf2_base_link_to_sensor_inv{tf2_base_link_to_sensor.inverse()};
172220
for (; it_x != it_x.end(); ++it_x, ++it_y, ++it_z, ++it_time_stamp) {
173221
for (;
174-
(velocity_report_it != std::end(velocity_report_queue_) - 1 &&
175-
*it_time_stamp > rclcpp::Time(velocity_report_it->header.stamp).seconds());
176-
++velocity_report_it) {
222+
(twist_it != std::end(twist_queue_) - 1 &&
223+
*it_time_stamp > rclcpp::Time(twist_it->header.stamp).seconds());
224+
++twist_it) {
177225
}
178226

179-
float v{static_cast<float>(velocity_report_it->longitudinal_velocity)};
180-
float w{static_cast<float>(velocity_report_it->heading_rate)};
227+
float v{static_cast<float>(twist_it->twist.linear.x)};
228+
float w{static_cast<float>(twist_it->twist.angular.z)};
181229

182-
if (std::abs(*it_time_stamp - rclcpp::Time(velocity_report_it->header.stamp).seconds()) > 0.1) {
230+
if (std::abs(*it_time_stamp - rclcpp::Time(twist_it->header.stamp).seconds()) > 0.1) {
183231
RCLCPP_WARN_STREAM_THROTTLE(
184232
get_logger(), *get_clock(), 10000 /* ms */,
185-
"velocity_report time_stamp is too late. Cloud not interpolate.");
233+
"twist time_stamp is too late. Could not interpolate.");
186234
v = 0.0f;
187235
w = 0.0f;
188236
}
189237

238+
if (use_imu_ && !angular_velocity_queue_.empty()) {
239+
for (;
240+
(imu_it != std::end(angular_velocity_queue_) - 1 &&
241+
*it_time_stamp > rclcpp::Time(imu_it->header.stamp).seconds());
242+
++imu_it) {
243+
}
244+
if (std::abs(*it_time_stamp - rclcpp::Time(imu_it->header.stamp).seconds()) > 0.1) {
245+
RCLCPP_WARN_STREAM_THROTTLE(
246+
get_logger(), *get_clock(), 10000 /* ms */,
247+
"imu time_stamp is too late. Could not interpolate.");
248+
} else {
249+
w = static_cast<float>(imu_it->vector.z);
250+
}
251+
}
252+
190253
const float time_offset = static_cast<float>(*it_time_stamp - prev_time_stamp_sec);
191254

192255
const tf2::Vector3 sensorTF_point{*it_x, *it_y, *it_z};

0 commit comments

Comments
 (0)