Skip to content

Commit 4cf7b3b

Browse files
authored
Merge pull request #3 from leggedrobotics/fix/multithreading
Fix/multithreading
2 parents 5bdf0cb + 79c7757 commit 4cf7b3b

File tree

2 files changed

+65
-43
lines changed

2 files changed

+65
-43
lines changed

elevation_mapping_cupy/include/elevation_mapping_cupy/elevation_mapping_ros.hpp

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@
77

88
// STL
99
#include <iostream>
10-
11-
// Boost
12-
#include <boost/thread/recursive_mutex.hpp>
10+
#include <mutex>
1311

1412
// Eigen
1513
#include <Eigen/Dense>
@@ -55,7 +53,7 @@ class ElevationMappingNode {
5553
void readParameters();
5654
void setupMapPublishers();
5755
void pointcloudCallback(const sensor_msgs::PointCloud2& cloud);
58-
void publishAsPointCloud();
56+
void publishAsPointCloud(const grid_map::GridMap& map) const;
5957
bool getSubmap(grid_map_msgs::GetGridMap::Request& request, grid_map_msgs::GetGridMap::Response& response);
6058
bool checkSafety(elevation_map_msgs::CheckSafety::Request& request, elevation_map_msgs::CheckSafety::Response& response);
6159
bool initializeMap(elevation_map_msgs::Initialize::Request& request, elevation_map_msgs::Initialize::Response& response);
@@ -66,16 +64,17 @@ class ElevationMappingNode {
6664
void updateVariance(const ros::TimerEvent&);
6765
void updateTime(const ros::TimerEvent&);
6866
void updateGridMap(const ros::TimerEvent&);
69-
void publishNormalAsArrow(const grid_map::GridMap& map);
67+
void publishNormalAsArrow(const grid_map::GridMap& map) const;
7068
void initializeWithTF();
7169
void publishMapToOdom(double error);
7270
void publishStatistics(const ros::TimerEvent&);
7371
void publishMapOfIndex(int index);
7472

75-
visualization_msgs::Marker vectorToArrowMarker(const Eigen::Vector3d& start, const Eigen::Vector3d& end, const int id);
73+
visualization_msgs::Marker vectorToArrowMarker(const Eigen::Vector3d& start, const Eigen::Vector3d& end, const int id) const;
7674
ros::NodeHandle nh_;
7775
std::vector<ros::Subscriber> pointcloudSubs_;
7876
std::vector<ros::Publisher> mapPubs_;
77+
tf::TransformBroadcaster tfBroadcaster_;
7978
ros::Publisher alivePub_;
8079
ros::Publisher pointPub_;
8180
ros::Publisher normalPub_;
@@ -97,7 +96,6 @@ class ElevationMappingNode {
9796
std::string mapFrameId_;
9897
std::string correctedMapFrameId_;
9998
std::string baseFrameId_;
100-
grid_map::GridMap gridMap_;
10199

102100
// map topics info
103101
std::vector<std::vector<std::string>> map_topics_;
@@ -116,20 +114,24 @@ class ElevationMappingNode {
116114
Eigen::Vector3d lowpassPosition_;
117115
Eigen::Vector4d lowpassOrientation_;
118116

119-
boost::recursive_mutex mapMutex_;
117+
std::mutex mapMutex_; // protects gridMap_
118+
grid_map::GridMap gridMap_;
119+
std::atomic_bool isGridmapUpdated_; // needs to be atomic (read is not protected by mapMutex_)
120120

121+
std::mutex errorMutex_; // protects positionError_, and orientationError_
121122
double positionError_;
122123
double orientationError_;
124+
123125
double positionAlpha_;
124126
double orientationAlpha_;
127+
125128
double recordableFps_;
126-
bool enablePointCloudPublishing_;
129+
std::atomic_bool enablePointCloudPublishing_;
127130
bool enableNormalArrowPublishing_;
128131
bool enableDriftCorrectedTFPublishing_;
129132
bool useInitializerAtStart_;
130-
bool isGridmapUpdated_;
131133
double initializeTfGridSize_;
132-
int pointCloudProcessCounter_;
134+
std::atomic_int pointCloudProcessCounter_;
133135
};
134136

135137
} // namespace elevation_mapping_cupy

elevation_mapping_cupy/src/elevation_mapping_ros.cpp

Lines changed: 52 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ ElevationMappingNode::ElevationMappingNode(ros::NodeHandle& nh)
3636
std::vector<std::string> pointcloud_topics;
3737
std::vector<std::string> map_topics;
3838
double recordableFps, updateVarianceFps, timeInterval, updatePoseFps, updateGridMapFps, publishStatisticsFps;
39+
bool enablePointCloudPublishing(false);
3940

4041
nh.param<std::vector<std::string>>("pointcloud_topics", pointcloud_topics, {"points"});
4142
nh.getParam("publishers", publishers);
@@ -55,10 +56,13 @@ ElevationMappingNode::ElevationMappingNode(ros::NodeHandle& nh)
5556
nh.param<double>("initialize_tf_grid_size", initializeTfGridSize_, 0.5);
5657
nh.param<double>("map_acquire_fps", updateGridMapFps, 5.0);
5758
nh.param<double>("publish_statistics_fps", publishStatisticsFps, 1.0);
58-
nh.param<bool>("enable_pointcloud_publishing", enablePointCloudPublishing_, false);
59+
nh.param<bool>("enable_pointcloud_publishing", enablePointCloudPublishing, false);
5960
nh.param<bool>("enable_normal_arrow_publishing", enableNormalArrowPublishing_, false);
6061
nh.param<bool>("enable_drift_corrected_TF_publishing", enableDriftCorrectedTFPublishing_, false);
6162
nh.param<bool>("use_initializer_at_start", useInitializerAtStart_, false);
63+
64+
enablePointCloudPublishing_ = enablePointCloudPublishing;
65+
6266
for (const auto& pointcloud_topic : pointcloud_topics) {
6367
ros::Subscriber sub = nh_.subscribe(pointcloud_topic, 1, &ElevationMappingNode::pointcloudCallback, this);
6468
pointcloudSubs_.push_back(sub);
@@ -184,25 +188,29 @@ void ElevationMappingNode::publishMapOfIndex(int index) {
184188
}
185189
grid_map_msgs::GridMap msg;
186190
std::vector<std::string> layers;
187-
for (const auto& layer : map_layers_[index]) {
188-
const bool is_layer_in_all = map_layers_all_.find(layer) != map_layers_all_.end();
189-
if (is_layer_in_all && gridMap_.exists(layer)) {
190-
layers.push_back(layer);
191-
} else if (map_.exists_layer(layer)) {
192-
// if there are layers which is not in the syncing layer.
193-
boost::recursive_mutex::scoped_lock scopedLockForGridMap(mapMutex_);
194-
ElevationMappingWrapper::RowMatrixXf map_data;
195-
map_.get_layer_data(layer, map_data);
196-
gridMap_.add(layer, map_data);
197-
layers.push_back(layer);
191+
192+
{ // need continuous lock between adding layers and converting to message. Otherwise updateGridmap can reset the data not in
193+
// map_layers_all_
194+
std::lock_guard<std::mutex> lock(mapMutex_);
195+
for (const auto& layer : map_layers_[index]) {
196+
const bool is_layer_in_all = map_layers_all_.find(layer) != map_layers_all_.end();
197+
if (is_layer_in_all && gridMap_.exists(layer)) {
198+
layers.push_back(layer);
199+
} else if (map_.exists_layer(layer)) {
200+
// if there are layers which is not in the syncing layer.
201+
ElevationMappingWrapper::RowMatrixXf map_data;
202+
map_.get_layer_data(layer, map_data);
203+
gridMap_.add(layer, map_data);
204+
layers.push_back(layer);
205+
}
198206
}
207+
if (layers.empty()) {
208+
return;
209+
}
210+
211+
grid_map::GridMapRosConverter::toMessage(gridMap_, layers, msg);
199212
}
200-
if (layers.empty()) {
201-
return;
202-
}
203-
boost::recursive_mutex::scoped_lock scopedLockForGridMap(mapMutex_);
204-
grid_map::GridMapRosConverter::toMessage(gridMap_, layers, msg);
205-
scopedLockForGridMap.unlock();
213+
206214
msg.basic_layers = map_basic_layers_[index];
207215
mapPubs_[index].publish(msg);
208216
}
@@ -226,16 +234,25 @@ void ElevationMappingNode::pointcloudCallback(const sensor_msgs::PointCloud2& cl
226234
ROS_ERROR("%s", ex.what());
227235
return;
228236
}
229-
map_.input(pointCloud, transformationSensorToMap.rotation(), transformationSensorToMap.translation(), positionError_, orientationError_);
237+
238+
double positionError{0.0};
239+
double orientationError{0.0};
240+
{
241+
std::lock_guard<std::mutex> lock(errorMutex_);
242+
positionError = positionError_;
243+
orientationError = orientationError_;
244+
}
245+
246+
map_.input(pointCloud, transformationSensorToMap.rotation(), transformationSensorToMap.translation(), positionError, orientationError);
230247

231248
if (enableDriftCorrectedTFPublishing_) {
232249
publishMapToOdom(map_.get_additive_mean_error());
233250
}
234251

235252
ROS_DEBUG_THROTTLE(1.0, "ElevationMap processed a point cloud (%i points) in %f sec.", static_cast<int>(pointCloud->size()),
236253
(ros::Time::now() - start).toSec());
237-
ROS_DEBUG_THROTTLE(1.0, "positionError: %f ", positionError_);
238-
ROS_DEBUG_THROTTLE(1.0, "orientationError: %f ", orientationError_);
254+
ROS_DEBUG_THROTTLE(1.0, "positionError: %f ", positionError);
255+
ROS_DEBUG_THROTTLE(1.0, "orientationError: %f ", orientationError);
239256
// This is used for publishing as statistics.
240257
pointCloudProcessCounter_++;
241258
}
@@ -259,18 +276,22 @@ void ElevationMappingNode::updatePose(const ros::TimerEvent&) {
259276
transformTf.getRotation().w());
260277
lowpassPosition_ = positionAlpha_ * position3 + (1 - positionAlpha_) * lowpassPosition_;
261278
lowpassOrientation_ = orientationAlpha_ * orientation + (1 - orientationAlpha_) * lowpassOrientation_;
262-
positionError_ = (position3 - lowpassPosition_).norm();
263-
orientationError_ = (orientation - lowpassOrientation_).norm();
279+
{
280+
std::lock_guard<std::mutex> lock(errorMutex_);
281+
positionError_ = (position3 - lowpassPosition_).norm();
282+
orientationError_ = (orientation - lowpassOrientation_).norm();
283+
}
284+
264285
if (useInitializerAtStart_) {
265286
ROS_INFO("Clearing map with initializer.");
266287
initializeWithTF();
267288
useInitializerAtStart_ = false;
268289
}
269290
}
270291

271-
void ElevationMappingNode::publishAsPointCloud() {
292+
void ElevationMappingNode::publishAsPointCloud(const grid_map::GridMap& map) const {
272293
sensor_msgs::PointCloud2 msg;
273-
grid_map::GridMapRosConverter::toPointCloud(gridMap_, "elevation", msg);
294+
grid_map::GridMapRosConverter::toPointCloud(map, "elevation", msg);
274295
pointPub_.publish(msg);
275296
}
276297

@@ -302,7 +323,7 @@ bool ElevationMappingNode::getSubmap(grid_map_msgs::GetGridMap::Request& request
302323
grid_map::Index index;
303324
grid_map::GridMap subMap;
304325
{
305-
boost::recursive_mutex::scoped_lock scopedLockForGridMap(mapMutex_);
326+
std::lock_guard<std::mutex> lock(mapMutex_);
306327
subMap = gridMap_.getSubmap(requestedSubmapPosition, requestedSubmapLength, index, isSuccess);
307328
}
308329
const auto& length = subMap.getLength();
@@ -453,14 +474,14 @@ void ElevationMappingNode::publishStatistics(const ros::TimerEvent&) {
453474

454475
void ElevationMappingNode::updateGridMap(const ros::TimerEvent&) {
455476
std::vector<std::string> layers(map_layers_all_.begin(), map_layers_all_.end());
456-
boost::recursive_mutex::scoped_lock scopedLockForGridMap(mapMutex_);
477+
std::lock_guard<std::mutex> lock(mapMutex_);
457478
map_.get_grid_map(gridMap_, layers);
458479
gridMap_.setTimestamp(ros::Time::now().toNSec());
459480
alivePub_.publish(std_msgs::Empty());
460481

461482
// Mostly debug purpose
462483
if (enablePointCloudPublishing_) {
463-
publishAsPointCloud();
484+
publishAsPointCloud(gridMap_);
464485
}
465486
if (enableNormalArrowPublishing_) {
466487
publishNormalAsArrow(gridMap_);
@@ -515,7 +536,7 @@ bool ElevationMappingNode::initializeMap(elevation_map_msgs::Initialize::Request
515536
return true;
516537
}
517538

518-
void ElevationMappingNode::publishNormalAsArrow(const grid_map::GridMap& map) {
539+
void ElevationMappingNode::publishNormalAsArrow(const grid_map::GridMap& map) const {
519540
auto startTime = ros::Time::now();
520541

521542
const auto& normalX = map["normal_x"];
@@ -545,7 +566,7 @@ void ElevationMappingNode::publishNormalAsArrow(const grid_map::GridMap& map) {
545566
}
546567

547568
visualization_msgs::Marker ElevationMappingNode::vectorToArrowMarker(const Eigen::Vector3d& start, const Eigen::Vector3d& end,
548-
const int id) {
569+
const int id) const {
549570
visualization_msgs::Marker marker;
550571
marker.header.frame_id = mapFrameId_;
551572
marker.header.stamp = ros::Time::now();
@@ -576,13 +597,12 @@ visualization_msgs::Marker ElevationMappingNode::vectorToArrowMarker(const Eigen
576597
}
577598

578599
void ElevationMappingNode::publishMapToOdom(double error) {
579-
static tf::TransformBroadcaster br;
580600
tf::Transform transform;
581601
transform.setOrigin(tf::Vector3(0.0, 0.0, error));
582602
tf::Quaternion q;
583603
q.setRPY(0, 0, 0);
584604
transform.setRotation(q);
585-
br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), mapFrameId_, correctedMapFrameId_));
605+
tfBroadcaster_.sendTransform(tf::StampedTransform(transform, ros::Time::now(), mapFrameId_, correctedMapFrameId_));
586606
}
587607

588608
} // namespace elevation_mapping_cupy

0 commit comments

Comments
 (0)