Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ndt_scan_matcher): estimate NDT covariance in real-time with limited initial positions #5338

Merged
merged 23 commits into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions localization/ndt_scan_matcher/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ One optional function is regularization. Please see the regularization chapter i
| `points_aligned` | `sensor_msgs::msg::PointCloud2` | [debug topic] pointcloud aligned by scan matching |
| `points_aligned_no_ground` | `sensor_msgs::msg::PointCloud2` | [debug topic] de-grounded pointcloud aligned by scan matching |
| `initial_pose_with_covariance` | `geometry_msgs::msg::PoseWithCovarianceStamped` | [debug topic] initial pose used in scan matching |
| `multi_ndt_pose` | `geometry_msgs::msg::PoseArray` | [debug topic] estimated poses from multiple initial poses in real-time covariance estimation |
| `multi_initial_pose` | `geometry_msgs::msg::PoseArray` | [debug topic] initial poses for real-time covariance estimation |
| `exe_time_ms` | `tier4_debug_msgs::msg::Float32Stamped` | [debug topic] execution time for scan matching [ms] |
| `transform_probability` | `tier4_debug_msgs::msg::Float32Stamped` | [debug topic] score of scan matching |
| `no_ground_transform_probability` | `tier4_debug_msgs::msg::Float32Stamped` | [debug topic] score of scan matching based on de-grounded LiDAR scan |
Expand Down Expand Up @@ -257,3 +259,26 @@ This is a function that uses de-grounded LiDAR scan to estimate the scan matchin
| ------------------------------------- | ------ | ------------------------------------------------------------------------------------- |
| `estimate_scores_for_degrounded_scan` | bool | Flag for using scan matching score based on de-grounded LiDAR scan (FALSE by default) |
| `z_margin_for_ground_removal` | double | Z-value margin for removal ground points |

## 2D real-time covariance estimation

### Abstract

Calculate 2D covariance (xx, xy, yx, yy) in real time using the NDT convergence from multiple initial poses.
The arrangement of multiple initial poses is efficiently limited by the Hessian matrix of the NDT score function.
In this implementation, the number of initial positions is fixed to simplify the code.
The covariance can be seen as error ellipse from ndt_pose_with_covariance setting on rviz2.
[original paper](https://www.fujipress.jp/jrm/rb/robot003500020435/).

Note that this function may spoil healthy system behavior if it consumes much calculation resources.

### Parameters
YamatoAndo marked this conversation as resolved.
Show resolved Hide resolved

initial_pose_offset_model is rotated around (x,y) = (0,0) in the direction of the first principal component of the Hessian matrix.
initial_pose_offset_model_x & initial_pose_offset_model_y must have the same number of elements.

| Name | Type | Description |
| -----------------------------| ------------------- | -----------------------------------------------------------------|
| `use_covariance_estimation` | bool | Flag for using real-time covariance estimation (FALSE by default)|
| `initial_pose_offset_model_x`| std::vector<double> | X-axis offset [m] |
| `initial_pose_offset_model_y`| std::vector<double> | Y-axis offset [m] |
YamatoAndo marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@
0.0, 0.0, 0.0, 0.0, 0.0, 0.000625,
]

# 2D Real-time covariance estimation with multiple searches (output_pose_covariance is the minimum value)
use_covariance_estimation: false

# Offset arrangement in covariance estimation [m]
# initial_pose_offset_model_x & initial_pose_offset_model_y must have the same number of elements.
initial_pose_offset_model_x: [0.0, 0.0, 0.5, -0.5, 1.0, -1.0]
initial_pose_offset_model_y: [0.5, -0.5, 0.0, 0.0, 0.0, 0.0]

# Regularization switch
regularization_enabled: false

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <rclcpp/rclcpp.hpp>

#include <diagnostic_msgs/msg/diagnostic_array.hpp>
#include <geometry_msgs/msg/pose_array.hpp>
#include <geometry_msgs/msg/pose_with_covariance_stamped.hpp>
#include <geometry_msgs/msg/twist_stamped.hpp>
#include <nav_msgs/msg/odometry.hpp>
Expand Down Expand Up @@ -104,7 +105,7 @@ class NDTScanMatcher : public rclcpp::Node
const rclcpp::Time & sensor_ros_time, const geometry_msgs::msg::Pose & result_pose_msg);
void publish_pose(
const rclcpp::Time & sensor_ros_time, const geometry_msgs::msg::Pose & result_pose_msg,
const bool is_converged);
const std::array<double, 36> & ndt_covariance, const bool is_converged);
void publish_point_cloud(
const rclcpp::Time & sensor_ros_time, const std::string & frame_id,
const pcl::shared_ptr<pcl::PointCloud<PointSource>> & sensor_points_in_map_ptr);
Expand All @@ -122,6 +123,10 @@ class NDTScanMatcher : public rclcpp::Node
bool validate_converged_param(
const double & transform_probability, const double & nearest_voxel_transformation_likelihood);

std::array<double, 36> estimate_covariance(
const pclomp::NdtResult & ndt_result, const Eigen::Matrix4f & initial_pose_matrix,
const rclcpp::Time & sensor_ros_time);

std::optional<Eigen::Matrix4f> interpolate_regularization_pose(
const rclcpp::Time & sensor_ros_time);
void add_regularization_pose(const rclcpp::Time & sensor_ros_time);
Expand All @@ -140,6 +145,8 @@ class NDTScanMatcher : public rclcpp::Node
ndt_pose_with_covariance_pub_;
rclcpp::Publisher<geometry_msgs::msg::PoseWithCovarianceStamped>::SharedPtr
initial_pose_with_covariance_pub_;
rclcpp::Publisher<geometry_msgs::msg::PoseArray>::SharedPtr multi_ndt_pose_pub_;
rclcpp::Publisher<geometry_msgs::msg::PoseArray>::SharedPtr multi_initial_pose_pub_;
rclcpp::Publisher<tier4_debug_msgs::msg::Float32Stamped>::SharedPtr exe_time_pub_;
rclcpp::Publisher<tier4_debug_msgs::msg::Float32Stamped>::SharedPtr transform_probability_pub_;
rclcpp::Publisher<tier4_debug_msgs::msg::Float32Stamped>::SharedPtr
Expand Down Expand Up @@ -186,6 +193,8 @@ class NDTScanMatcher : public rclcpp::Node
double initial_pose_distance_tolerance_m_;
float inversion_vector_threshold_;
float oscillation_threshold_;
bool use_cov_estimation_;
std::vector<Eigen::Vector2d> initial_pose_offset_model_;
std::array<double, 36> output_pose_covariance_;

std::deque<geometry_msgs::msg::PoseWithCovarianceStamped::ConstSharedPtr>
Expand Down
143 changes: 135 additions & 8 deletions localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2015-2019 Autoware Foundation

Check notice on line 1 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

✅ No longer an issue: Primitive Obsession

The ratio of primivite types in function arguments is no longer above the threshold
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -53,6 +53,32 @@
return tier4_debug_msgs::build<T>().stamp(stamp).data(data);
}

std::vector<Eigen::Vector2d> create_initial_pose_offset_model(

Check warning on line 56 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L56

Added line #L56 was not covered by tests
const std::vector<double> & x, const std::vector<double> & y)
{
int size = x.size();
std::vector<Eigen::Vector2d> initial_pose_offset_model(size);
for (int i = 0; i < size; i++) {
initial_pose_offset_model[i].x() = x[i];
initial_pose_offset_model[i].y() = y[i];

Check warning on line 63 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L59-L63

Added lines #L59 - L63 were not covered by tests
}

return initial_pose_offset_model;

Check warning on line 66 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L66

Added line #L66 was not covered by tests
}

Eigen::Matrix2d find_rotation_matrix_aligning_covariance_to_principal_axes(

Check warning on line 69 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L69

Added line #L69 was not covered by tests
const Eigen::Matrix2d & matrix)
{
const Eigen::SelfAdjointEigenSolver<Eigen::Matrix2d> eigensolver(matrix);
if (eigensolver.info() == Eigen::Success) {

Check warning on line 73 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L73

Added line #L73 was not covered by tests
const Eigen::Vector2d eigen_vec = eigensolver.eigenvectors().col(0);
const double th = std::atan2(eigen_vec.y(), eigen_vec.x());
return Eigen::Rotation2Dd(th).toRotationMatrix();

Check warning on line 76 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L75-L76

Added lines #L75 - L76 were not covered by tests
} else {
throw std::runtime_error("Eigen solver failed. Return output_pose_covariance value.");

Check warning on line 78 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L78

Added line #L78 was not covered by tests
}
}

bool validate_local_optimal_solution_oscillation(
const std::vector<geometry_msgs::msg::Pose> & result_pose_msg_array,
const float oscillation_threshold, const float inversion_vector_threshold)
Expand Down Expand Up @@ -141,6 +167,24 @@
initial_pose_distance_tolerance_m_ =
this->declare_parameter<double>("initial_pose_distance_tolerance_m");

use_cov_estimation_ = this->declare_parameter<bool>("use_covariance_estimation");
if (use_cov_estimation_) {

Check warning on line 171 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L170-L171

Added lines #L170 - L171 were not covered by tests
std::vector<double> initial_pose_offset_model_x =
this->declare_parameter<std::vector<double>>("initial_pose_offset_model_x");

Check warning on line 173 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L173

Added line #L173 was not covered by tests
std::vector<double> initial_pose_offset_model_y =
this->declare_parameter<std::vector<double>>("initial_pose_offset_model_y");

Check warning on line 175 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L175

Added line #L175 was not covered by tests

if (initial_pose_offset_model_x.size() == initial_pose_offset_model_y.size()) {

Check warning on line 177 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L177

Added line #L177 was not covered by tests
initial_pose_offset_model_ =
create_initial_pose_offset_model(initial_pose_offset_model_x, initial_pose_offset_model_y);

Check warning on line 179 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L179

Added line #L179 was not covered by tests
} else {
RCLCPP_WARN(

Check warning on line 181 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L181

Added line #L181 was not covered by tests
get_logger(),
"Invalid initial pose offset model parameters. Disable covariance estimation.");
use_cov_estimation_ = false;

Check warning on line 184 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L184

Added line #L184 was not covered by tests
SakodaShintaro marked this conversation as resolved.
Show resolved Hide resolved
}
}

std::vector<double> output_pose_covariance =
this->declare_parameter<std::vector<double>>("output_pose_covariance");
for (std::size_t i = 0; i < output_pose_covariance.size(); ++i) {
Expand Down Expand Up @@ -191,6 +235,9 @@
initial_pose_with_covariance_pub_ =
this->create_publisher<geometry_msgs::msg::PoseWithCovarianceStamped>(
"initial_pose_with_covariance", 10);
multi_ndt_pose_pub_ = this->create_publisher<geometry_msgs::msg::PoseArray>("multi_ndt_pose", 10);

Check warning on line 238 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L238

Added line #L238 was not covered by tests
multi_initial_pose_pub_ =
this->create_publisher<geometry_msgs::msg::PoseArray>("multi_initial_pose", 10);

Check warning on line 240 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L240

Added line #L240 was not covered by tests
exe_time_pub_ = this->create_publisher<tier4_debug_msgs::msg::Float32Stamped>("exe_time_ms", 10);
transform_probability_pub_ =
this->create_publisher<tier4_debug_msgs::msg::Float32Stamped>("transform_probability", 10);
Expand Down Expand Up @@ -434,38 +481,46 @@
ndt_ptr_->align(*output_cloud, initial_pose_matrix);
const pclomp::NdtResult ndt_result = ndt_ptr_->getResult();
(*state_ptr_)["state"] = "Sleeping";

const auto exe_end_time = std::chrono::system_clock::now();
const auto duration_micro_sec =
std::chrono::duration_cast<std::chrono::microseconds>(exe_end_time - exe_start_time).count();
const auto exe_time = static_cast<float>(duration_micro_sec) / 1000.0f;

const geometry_msgs::msg::Pose result_pose_msg = matrix4f_to_pose(ndt_result.pose);
std::vector<geometry_msgs::msg::Pose> transformation_msg_array;
for (const auto & pose_matrix : ndt_result.transformation_array) {
geometry_msgs::msg::Pose pose_ros = matrix4f_to_pose(pose_matrix);
transformation_msg_array.push_back(pose_ros);
}

// perform several validations
bool is_ok_iteration_num =
validate_num_iteration(ndt_result.iteration_num, ndt_ptr_->getMaximumIterations());
bool is_local_optimal_solution_oscillation = false;
if (!is_ok_iteration_num) {
is_local_optimal_solution_oscillation = validate_local_optimal_solution_oscillation(
transformation_msg_array, oscillation_threshold_, inversion_vector_threshold_);
}
bool is_ok_converged_param = validate_converged_param(
ndt_result.transform_probability, ndt_result.nearest_voxel_transformation_likelihood);
bool is_converged = is_ok_iteration_num && is_ok_converged_param;
static size_t skipping_publish_num = 0;
if (is_converged) {
skipping_publish_num = 0;
} else {
++skipping_publish_num;
RCLCPP_WARN(get_logger(), "Not Converged");
}

// covariance estimation
std::array<double, 36> ndt_covariance = output_pose_covariance_;
if (is_converged && use_cov_estimation_) {

Check warning on line 513 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L512-L513

Added lines #L512 - L513 were not covered by tests
const auto estimated_covariance =
estimate_covariance(ndt_result, initial_pose_matrix, sensor_ros_time);
ndt_covariance = estimated_covariance;

Check warning on line 516 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L515-L516

Added lines #L515 - L516 were not covered by tests
}

const auto exe_end_time = std::chrono::system_clock::now();

Check warning on line 519 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L519

Added line #L519 was not covered by tests
const auto duration_micro_sec =
std::chrono::duration_cast<std::chrono::microseconds>(exe_end_time - exe_start_time).count();
const auto exe_time = static_cast<float>(duration_micro_sec) / 1000.0f;

Check warning on line 522 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L522

Added line #L522 was not covered by tests

// publish
initial_pose_with_covariance_pub_->publish(interpolator.get_current_pose());
exe_time_pub_->publish(make_float32_stamped(sensor_ros_time, exe_time));
Expand All @@ -475,7 +530,7 @@
make_float32_stamped(sensor_ros_time, ndt_result.nearest_voxel_transformation_likelihood));
iteration_num_pub_->publish(make_int32_stamped(sensor_ros_time, ndt_result.iteration_num));
publish_tf(sensor_ros_time, result_pose_msg);
publish_pose(sensor_ros_time, result_pose_msg, is_converged);
publish_pose(sensor_ros_time, result_pose_msg, ndt_covariance, is_converged);

Check warning on line 533 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (main)

❌ Getting worse: Complex Method

NDTScanMatcher::callback_sensor_points increases in cyclomatic complexity from 16 to 18, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.

Check warning on line 533 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L533

Added line #L533 was not covered by tests
publish_marker(sensor_ros_time, transformation_msg_array);
publish_initial_to_result(
sensor_ros_time, result_pose_msg, interpolator.get_current_pose(), interpolator.get_old_pose(),
Expand Down Expand Up @@ -558,7 +613,7 @@

void NDTScanMatcher::publish_pose(
const rclcpp::Time & sensor_ros_time, const geometry_msgs::msg::Pose & result_pose_msg,
const bool is_converged)
const std::array<double, 36> & ndt_covariance, const bool is_converged)
{
geometry_msgs::msg::PoseStamped result_pose_stamped_msg;
result_pose_stamped_msg.header.stamp = sensor_ros_time;
Expand All @@ -569,7 +624,7 @@
result_pose_with_cov_msg.header.stamp = sensor_ros_time;
result_pose_with_cov_msg.header.frame_id = map_frame_;
result_pose_with_cov_msg.pose.pose = result_pose_msg;
result_pose_with_cov_msg.pose.covariance = output_pose_covariance_;
result_pose_with_cov_msg.pose.covariance = ndt_covariance;

Check warning on line 627 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L627

Added line #L627 was not covered by tests

if (is_converged) {
ndt_pose_pub_->publish(result_pose_stamped_msg);
Expand Down Expand Up @@ -692,6 +747,78 @@
return is_ok_converged_param;
}

std::array<double, 36> NDTScanMatcher::estimate_covariance(

Check warning on line 750 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L750

Added line #L750 was not covered by tests
const pclomp::NdtResult & ndt_result, const Eigen::Matrix4f & initial_pose_matrix,
const rclcpp::Time & sensor_ros_time)
{
Eigen::Matrix2d rot = Eigen::Matrix2d::Identity();
try {
rot = find_rotation_matrix_aligning_covariance_to_principal_axes(
ndt_result.hessian.inverse().block(0, 0, 2, 2));
} catch (const std::exception & e) {
RCLCPP_WARN(get_logger(), e.what());
return output_pose_covariance_;
}

Check warning on line 761 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L756-L761

Added lines #L756 - L761 were not covered by tests

// first result is added to mean
const int n = initial_pose_offset_model_.size() + 1;

Check warning on line 764 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L764

Added line #L764 was not covered by tests
const Eigen::Vector2d ndt_pose_2d(ndt_result.pose(0, 3), ndt_result.pose(1, 3));
Eigen::Vector2d mean = ndt_pose_2d;
std::vector<Eigen::Vector2d> ndt_pose_2d_vec;
ndt_pose_2d_vec.reserve(n);
ndt_pose_2d_vec.emplace_back(ndt_pose_2d);

Check warning on line 769 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L768-L769

Added lines #L768 - L769 were not covered by tests

geometry_msgs::msg::PoseArray multi_ndt_result_msg;
geometry_msgs::msg::PoseArray multi_initial_pose_msg;
multi_ndt_result_msg.header.stamp = sensor_ros_time;
multi_ndt_result_msg.header.frame_id = map_frame_;
multi_initial_pose_msg.header.stamp = sensor_ros_time;

Check warning on line 775 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L773-L775

Added lines #L773 - L775 were not covered by tests
KYabuuchi marked this conversation as resolved.
Show resolved Hide resolved
multi_initial_pose_msg.header.frame_id = map_frame_;
multi_ndt_result_msg.poses.push_back(matrix4f_to_pose(ndt_result.pose));
multi_initial_pose_msg.poses.push_back(matrix4f_to_pose(initial_pose_matrix));

Check warning on line 778 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L777-L778

Added lines #L777 - L778 were not covered by tests

// multiple searches
for (const auto & pose_offset : initial_pose_offset_model_) {

Check warning on line 781 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L781

Added line #L781 was not covered by tests
const Eigen::Vector2d rotated_pose_offset_2d = rot * pose_offset;

Eigen::Matrix4f sub_initial_pose_matrix(Eigen::Matrix4f::Identity());
sub_initial_pose_matrix = ndt_result.pose;
sub_initial_pose_matrix(0, 3) += static_cast<float>(rotated_pose_offset_2d.x());
sub_initial_pose_matrix(1, 3) += static_cast<float>(rotated_pose_offset_2d.y());

Check warning on line 787 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L786-L787

Added lines #L786 - L787 were not covered by tests

auto sub_output_cloud = std::make_shared<pcl::PointCloud<PointSource>>();
ndt_ptr_->align(*sub_output_cloud, sub_initial_pose_matrix);
const Eigen::Matrix4f sub_ndt_result = ndt_ptr_->getResult().pose;

Check warning on line 791 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L790-L791

Added lines #L790 - L791 were not covered by tests

const Eigen::Vector2d sub_ndt_pose_2d = sub_ndt_result.topRightCorner<2, 1>().cast<double>();
mean += sub_ndt_pose_2d;
ndt_pose_2d_vec.emplace_back(sub_ndt_pose_2d);

Check warning on line 795 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L795

Added line #L795 was not covered by tests

multi_ndt_result_msg.poses.push_back(matrix4f_to_pose(sub_ndt_result));
multi_initial_pose_msg.poses.push_back(matrix4f_to_pose(sub_initial_pose_matrix));

Check warning on line 798 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L797-L798

Added lines #L797 - L798 were not covered by tests
}

// calculate the covariance matrix
mean /= n;

Check warning on line 802 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L802

Added line #L802 was not covered by tests
Eigen::Matrix2d pca_covariance = Eigen::Matrix2d::Zero();
for (const auto & temp_ndt_pose_2d : ndt_pose_2d_vec) {

Check warning on line 804 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L804

Added line #L804 was not covered by tests
const Eigen::Vector2d diff_2d = temp_ndt_pose_2d - mean;
pca_covariance += diff_2d * diff_2d.transpose();
}
pca_covariance /= (n - 1); // unbiased covariance

Check warning on line 808 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L808

Added line #L808 was not covered by tests

std::array<double, 36> ndt_covariance = output_pose_covariance_;
ndt_covariance[0 + 6 * 0] += pca_covariance(0, 0);
ndt_covariance[1 + 6 * 0] += pca_covariance(1, 0);
ndt_covariance[0 + 6 * 1] += pca_covariance(0, 1);
ndt_covariance[1 + 6 * 1] += pca_covariance(1, 1);

Check warning on line 814 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L810-L814

Added lines #L810 - L814 were not covered by tests

multi_ndt_pose_pub_->publish(multi_ndt_result_msg);
multi_initial_pose_pub_->publish(multi_initial_pose_msg);

Check warning on line 817 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L816-L817

Added lines #L816 - L817 were not covered by tests

return ndt_covariance;
}

Check warning on line 820 in localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp

View check run for this annotation

Codecov / codecov/patch

localization/ndt_scan_matcher/src/ndt_scan_matcher_core.cpp#L819-L820

Added lines #L819 - L820 were not covered by tests

std::optional<Eigen::Matrix4f> NDTScanMatcher::interpolate_regularization_pose(
const rclcpp::Time & sensor_ros_time)
{
Expand Down
Loading