Skip to content

Commit 60b8f0a

Browse files
anhnv3991pre-commit-ci[bot]
authored andcommitted
feat(ndt_scan_matcher): smooth ndt map update (#6394)
* Fixed conflicts Signed-off-by: anhnv3991 <anh.nguyen.2@tier4.jp> * style(pre-commit): autofix * Remove unnecessary TODO Signed-off-by: anhnv3991 <anh.nguyen.2@tier4.jp> * Removed unused debug variable and rename rebuild_ to need_rebuild_ for better understanding Signed-off-by: anhnv3991 <anh.nguyen.2@tier4.jp> * Replace pointer to ndt by reference, output error when the input ndt_ptr is null Signed-off-by: anhnv3991 <anh.nguyen.2@tier4.jp> * style(pre-commit): autofix * Fix error message Signed-off-by: anhnv3991 <anh.nguyen.2@tier4.jp> * style(pre-commit): autofix --------- Signed-off-by: anhnv3991 <anh.nguyen.2@tier4.jp> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Signed-off-by: Kotaro Yoshimoto <pythagora.yoshimoto@gmail.com>
1 parent 3b06c9c commit 60b8f0a

File tree

2 files changed

+86
-33
lines changed

2 files changed

+86
-33
lines changed

localization/ndt_scan_matcher/include/ndt_scan_matcher/map_update_module.hpp

+12-9
Original file line numberDiff line numberDiff line change
@@ -36,44 +36,47 @@
3636
#include <memory>
3737
#include <optional>
3838
#include <string>
39+
#include <thread>
3940
#include <vector>
4041

4142
class MapUpdateModule
4243
{
4344
using PointSource = pcl::PointXYZ;
4445
using PointTarget = pcl::PointXYZ;
45-
using NormalDistributionsTransform =
46-
pclomp::MultiGridNormalDistributionsTransform<PointSource, PointTarget>;
46+
using NdtType = pclomp::MultiGridNormalDistributionsTransform<PointSource, PointTarget>;
47+
using NdtPtrType = std::shared_ptr<NdtType>;
4748

4849
public:
4950
MapUpdateModule(
50-
rclcpp::Node * node, std::mutex * ndt_ptr_mutex,
51-
std::shared_ptr<NormalDistributionsTransform> ndt_ptr,
51+
rclcpp::Node * node, std::mutex * ndt_ptr_mutex, NdtPtrType & ndt_ptr,
5252
HyperParameters::DynamicMapLoading param);
5353

5454
private:
5555
friend class NDTScanMatcher;
5656

57-
void update_ndt(
58-
const std::vector<autoware_map_msgs::msg::PointCloudMapCellWithID> & maps_to_add,
59-
const std::vector<std::string> & map_ids_to_remove);
57+
// Update the specified NDT
58+
void update_ndt(const geometry_msgs::msg::Point & position, NdtType & ndt);
6059
void update_map(const geometry_msgs::msg::Point & position);
61-
[[nodiscard]] bool should_update_map(const geometry_msgs::msg::Point & position) const;
60+
[[nodiscard]] bool should_update_map(const geometry_msgs::msg::Point & position);
6261
void publish_partial_pcd_map();
6362

6463
rclcpp::Publisher<sensor_msgs::msg::PointCloud2>::SharedPtr loaded_pcd_pub_;
6564

6665
rclcpp::Client<autoware_map_msgs::srv::GetDifferentialPointCloudMap>::SharedPtr
6766
pcd_loader_client_;
6867

69-
std::shared_ptr<NormalDistributionsTransform> ndt_ptr_;
68+
NdtPtrType & ndt_ptr_;
7069
std::mutex * ndt_ptr_mutex_;
7170
rclcpp::Logger logger_;
7271
rclcpp::Clock::SharedPtr clock_;
7372

7473
std::optional<geometry_msgs::msg::Point> last_update_position_ = std::nullopt;
7574

7675
HyperParameters::DynamicMapLoading param_;
76+
77+
// Indicate if there is a prefetch thread waiting for being collected
78+
NdtPtrType secondary_ndt_ptr_;
79+
bool need_rebuild_;
7780
};
7881

7982
#endif // NDT_SCAN_MATCHER__MAP_UPDATE_MODULE_HPP_

localization/ndt_scan_matcher/src/map_update_module.cpp

+74-24
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515
#include "ndt_scan_matcher/map_update_module.hpp"
1616

1717
MapUpdateModule::MapUpdateModule(
18-
rclcpp::Node * node, std::mutex * ndt_ptr_mutex,
19-
std::shared_ptr<NormalDistributionsTransform> ndt_ptr, HyperParameters::DynamicMapLoading param)
20-
: ndt_ptr_(std::move(ndt_ptr)),
18+
rclcpp::Node * node, std::mutex * ndt_ptr_mutex, NdtPtrType & ndt_ptr,
19+
HyperParameters::DynamicMapLoading param)
20+
: ndt_ptr_(ndt_ptr),
2121
ndt_ptr_mutex_(ndt_ptr_mutex),
2222
logger_(node->get_logger()),
2323
clock_(node->get_clock()),
@@ -28,29 +28,90 @@ MapUpdateModule::MapUpdateModule(
2828

2929
pcd_loader_client_ =
3030
node->create_client<autoware_map_msgs::srv::GetDifferentialPointCloudMap>("pcd_loader_service");
31+
32+
secondary_ndt_ptr_.reset(new NdtType);
33+
34+
if (ndt_ptr_) {
35+
*secondary_ndt_ptr_ = *ndt_ptr_;
36+
} else {
37+
RCLCPP_ERROR_STREAM_THROTTLE(logger_, *clock_, 1000, "Attempt to update a null NDT pointer.");
38+
}
39+
40+
// Initially, a direct map update on ndt_ptr_ is needed.
41+
// ndt_ptr_'s mutex is locked until it is fully rebuilt.
42+
// From the second update, the update is done on secondary_ndt_ptr_,
43+
// and ndt_ptr_ is only locked when swapping its pointer with
44+
// secondary_ndt_ptr_.
45+
need_rebuild_ = true;
3146
}
3247

33-
bool MapUpdateModule::should_update_map(const geometry_msgs::msg::Point & position) const
48+
bool MapUpdateModule::should_update_map(const geometry_msgs::msg::Point & position)
3449
{
3550
if (last_update_position_ == std::nullopt) {
3651
return false;
3752
}
53+
3854
const double dx = position.x - last_update_position_.value().x;
3955
const double dy = position.y - last_update_position_.value().y;
4056
const double distance = std::hypot(dx, dy);
4157
if (distance + param_.lidar_radius > param_.map_radius) {
4258
RCLCPP_ERROR_STREAM_THROTTLE(logger_, *clock_, 1000, "Dynamic map loading is not keeping up.");
59+
// If the map does not keep up with the current position,
60+
// lock ndt_ptr_ entirely until it is fully rebuilt.
61+
need_rebuild_ = true;
4362
}
63+
4464
return distance > param_.update_distance;
4565
}
4666

4767
void MapUpdateModule::update_map(const geometry_msgs::msg::Point & position)
68+
{
69+
// If the current position is super far from the previous loading position,
70+
// lock and rebuild ndt_ptr_
71+
if (need_rebuild_) {
72+
ndt_ptr_mutex_->lock();
73+
auto param = ndt_ptr_->getParams();
74+
75+
ndt_ptr_.reset(new NdtType);
76+
77+
ndt_ptr_->setParams(param);
78+
79+
update_ndt(position, *ndt_ptr_);
80+
ndt_ptr_mutex_->unlock();
81+
need_rebuild_ = false;
82+
} else {
83+
// Load map to the secondary_ndt_ptr, which does not require a mutex lock
84+
// Since the update of the secondary ndt ptr and the NDT align (done on
85+
// the main ndt_ptr_) overlap, the latency of updating/alignment reduces partly.
86+
// If the updating is done the main ndt_ptr_, either the update or the NDT
87+
// align will be blocked by the other.
88+
update_ndt(position, *secondary_ndt_ptr_);
89+
90+
ndt_ptr_mutex_->lock();
91+
auto input_source = ndt_ptr_->getInputSource();
92+
ndt_ptr_ = secondary_ndt_ptr_;
93+
ndt_ptr_->setInputSource(input_source);
94+
ndt_ptr_mutex_->unlock();
95+
}
96+
97+
secondary_ndt_ptr_.reset(new NdtType);
98+
*secondary_ndt_ptr_ = *ndt_ptr_;
99+
100+
// Memorize the position of the last update
101+
last_update_position_ = position;
102+
103+
// Publish the new ndt maps
104+
publish_partial_pcd_map();
105+
}
106+
107+
void MapUpdateModule::update_ndt(const geometry_msgs::msg::Point & position, NdtType & ndt)
48108
{
49109
auto request = std::make_shared<autoware_map_msgs::srv::GetDifferentialPointCloudMap::Request>();
110+
50111
request->area.center_x = static_cast<float>(position.x);
51112
request->area.center_y = static_cast<float>(position.y);
52113
request->area.radius = static_cast<float>(param_.map_radius);
53-
request->cached_ids = ndt_ptr_->getCurrentMapIDs();
114+
request->cached_ids = ndt.getCurrentMapIDs();
54115

55116
while (!pcd_loader_client_->wait_for_service(std::chrono::seconds(1)) && rclcpp::ok()) {
56117
RCLCPP_INFO(logger_, "Waiting for pcd loader service. Check the pointcloud_map_loader.");
@@ -69,60 +130,49 @@ void MapUpdateModule::update_map(const geometry_msgs::msg::Point & position)
69130
}
70131
status = result.wait_for(std::chrono::seconds(1));
71132
}
72-
update_ndt(result.get()->new_pointcloud_with_ids, result.get()->ids_to_remove);
73-
last_update_position_ = position;
74-
}
75133

76-
void MapUpdateModule::update_ndt(
77-
const std::vector<autoware_map_msgs::msg::PointCloudMapCellWithID> & maps_to_add,
78-
const std::vector<std::string> & map_ids_to_remove)
79-
{
134+
auto & maps_to_add = result.get()->new_pointcloud_with_ids;
135+
auto & map_ids_to_remove = result.get()->ids_to_remove;
136+
80137
RCLCPP_INFO(
81138
logger_, "Update map (Add: %lu, Remove: %lu)", maps_to_add.size(), map_ids_to_remove.size());
82139
if (maps_to_add.empty() && map_ids_to_remove.empty()) {
83140
RCLCPP_INFO(logger_, "Skip map update");
84141
return;
85142
}
86-
const auto exe_start_time = std::chrono::system_clock::now();
87143

144+
const auto exe_start_time = std::chrono::system_clock::now();
88145
const size_t add_size = maps_to_add.size();
89-
90146
// Perform heavy processing outside of the lock scope
91147
std::vector<pcl::shared_ptr<pcl::PointCloud<PointTarget>>> points_pcl(add_size);
148+
92149
for (size_t i = 0; i < add_size; i++) {
93150
points_pcl[i] = pcl::make_shared<pcl::PointCloud<PointTarget>>();
94151
pcl::fromROSMsg(maps_to_add[i].pointcloud, *points_pcl[i]);
95152
}
96153

97-
(*ndt_ptr_mutex_).lock();
98-
99154
// Add pcd
100155
for (size_t i = 0; i < add_size; i++) {
101-
ndt_ptr_->addTarget(points_pcl[i], maps_to_add[i].cell_id);
156+
ndt.addTarget(points_pcl[i], maps_to_add[i].cell_id);
102157
}
103158

104159
// Remove pcd
105160
for (const std::string & map_id_to_remove : map_ids_to_remove) {
106-
ndt_ptr_->removeTarget(map_id_to_remove);
161+
ndt.removeTarget(map_id_to_remove);
107162
}
108163

109-
ndt_ptr_->createVoxelKdtree();
110-
111-
(*ndt_ptr_mutex_).unlock();
164+
ndt.createVoxelKdtree();
112165

113166
const auto exe_end_time = std::chrono::system_clock::now();
114167
const auto duration_micro_sec =
115168
std::chrono::duration_cast<std::chrono::microseconds>(exe_end_time - exe_start_time).count();
116169
const auto exe_time = static_cast<double>(duration_micro_sec) / 1000.0;
117170
RCLCPP_INFO(logger_, "Time duration for creating new ndt_ptr: %lf [ms]", exe_time);
118-
119-
publish_partial_pcd_map();
120171
}
121172

122173
void MapUpdateModule::publish_partial_pcd_map()
123174
{
124175
pcl::PointCloud<PointTarget> map_pcl = ndt_ptr_->getVoxelPCD();
125-
126176
sensor_msgs::msg::PointCloud2 map_msg;
127177
pcl::toROSMsg(map_pcl, map_msg);
128178
map_msg.header.frame_id = "map";

0 commit comments

Comments
 (0)