Skip to content

Commit 3bc462b

Browse files
committed
ObservationBuffer stores shared ptrs of observations to avoid copies when queried
Signed-off-by: Fabian König <fabiankoenig@gmail.com>
1 parent bfc3cf7 commit 3bc462b

File tree

10 files changed

+228
-91
lines changed

10 files changed

+228
-91
lines changed

nav2_costmap_2d/include/nav2_costmap_2d/observation.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#ifndef NAV2_COSTMAP_2D__OBSERVATION_HPP_
3333
#define NAV2_COSTMAP_2D__OBSERVATION_HPP_
3434

35+
#include <utility>
3536
#include <geometry_msgs/msg/point.hpp>
3637
#include <sensor_msgs/msg/point_cloud2.hpp>
3738
#include <rclcpp/macros.hpp>

nav2_costmap_2d/include/nav2_costmap_2d/observation_buffer.hpp

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,6 @@ class ObservationBuffer
8787
std::string sensor_frame,
8888
tf2::Duration tf_tolerance);
8989

90-
/**
91-
* @brief Destructor... cleans up
92-
*/
93-
~ObservationBuffer();
94-
9590
/**
9691
* @brief Transforms a PointCloud to the global frame and buffers it
9792
* <b>Note: The burden is on the user to make sure the transform is available... ie they should use a MessageNotifier</b>
@@ -103,7 +98,7 @@ class ObservationBuffer
10398
* @brief Pushes copies of all current observations onto the end of the vector passed in
10499
* @param observations The vector to be filled
105100
*/
106-
void getObservations(std::vector<Observation> & observations);
101+
void getObservations(std::vector<Observation::ConstSharedPtr> & observations);
107102

108103
/**
109104
* @brief Check if the observation buffer is being update at its expected rate
@@ -146,7 +141,7 @@ class ObservationBuffer
146141
rclcpp::Time last_updated_;
147142
std::string global_frame_;
148143
std::string sensor_frame_;
149-
std::list<Observation> observation_list_;
144+
std::list<Observation::ConstSharedPtr> observation_list_;
150145
std::string topic_name_;
151146
double min_obstacle_height_, max_obstacle_height_;
152147
std::recursive_mutex lock_; ///< @brief A lock for accessing data in callbacks safely

nav2_costmap_2d/include/nav2_costmap_2d/obstacle_layer.hpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ class ObstacleLayer : public CostmapLayer
174174
const std::shared_ptr<nav2_costmap_2d::ObservationBuffer> & buffer);
175175

176176
// for testing purposes
177-
void addStaticObservation(nav2_costmap_2d::Observation & obs, bool marking, bool clearing);
177+
void addStaticObservation(nav2_costmap_2d::Observation obs, bool marking, bool clearing);
178178
void clearStaticObservations(bool marking, bool clearing);
179179

180180
protected:
@@ -184,15 +184,15 @@ class ObstacleLayer : public CostmapLayer
184184
* @return True if all the observation buffers are current, false otherwise
185185
*/
186186
bool getMarkingObservations(
187-
std::vector<nav2_costmap_2d::Observation> & marking_observations) const;
187+
std::vector<nav2_costmap_2d::Observation::ConstSharedPtr> & marking_observations) const;
188188

189189
/**
190190
* @brief Get the observations used to clear space
191191
* @param clearing_observations A reference to a vector that will be populated with the observations
192192
* @return True if all the observation buffers are current, false otherwise
193193
*/
194194
bool getClearingObservations(
195-
std::vector<nav2_costmap_2d::Observation> & clearing_observations) const;
195+
std::vector<nav2_costmap_2d::Observation::ConstSharedPtr> & clearing_observations) const;
196196

197197
/**
198198
* @brief Clear freespace based on one observation
@@ -255,8 +255,8 @@ class ObstacleLayer : public CostmapLayer
255255
rclcpp::node_interfaces::OnSetParametersCallbackHandle::SharedPtr dyn_params_handler_;
256256

257257
// Used only for testing purposes
258-
std::vector<nav2_costmap_2d::Observation> static_clearing_observations_;
259-
std::vector<nav2_costmap_2d::Observation> static_marking_observations_;
258+
std::vector<nav2_costmap_2d::Observation::ConstSharedPtr> static_clearing_observations_;
259+
std::vector<nav2_costmap_2d::Observation::ConstSharedPtr> static_marking_observations_;
260260

261261
bool rolling_window_;
262262
bool was_reset_;

nav2_costmap_2d/plugins/costmap_filters/costmap_filter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ unsigned char CostmapFilter::getMaskCost(
217217
{
218218
const unsigned int index = my * filter_mask->info.width + mx;
219219

220-
const char data = filter_mask->data[index];
220+
const auto data = filter_mask->data[index];
221221
if (data == nav2_util::OCC_GRID_UNKNOWN) {
222222
return NO_INFORMATION;
223223
} else {

nav2_costmap_2d/plugins/obstacle_layer.cpp

Lines changed: 30 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -202,15 +202,13 @@ void ObstacleLayer::onInitialize()
202202

203203
// create an observation buffer
204204
observation_buffers_.push_back(
205-
std::shared_ptr<ObservationBuffer
206-
>(
207-
new ObservationBuffer(
208-
node, topic, observation_keep_time, expected_update_rate,
205+
std::make_shared<ObservationBuffer>(node, topic, observation_keep_time,
206+
expected_update_rate,
209207
min_obstacle_height,
210208
max_obstacle_height, obstacle_max_range, obstacle_min_range, raytrace_max_range,
211209
raytrace_min_range, *tf_,
212210
global_frame_,
213-
sensor_frame, tf2::durationFromSec(transform_tolerance))));
211+
sensor_frame, tf2::durationFromSec(transform_tolerance)));
214212

215213
// check if we'll add this buffer to our marking observation buffers
216214
if (marking) {
@@ -388,7 +386,7 @@ ObstacleLayer::dynamicParametersCallback(
388386
void
389387
ObstacleLayer::laserScanCallback(
390388
sensor_msgs::msg::LaserScan::ConstSharedPtr message,
391-
const std::shared_ptr<nav2_costmap_2d::ObservationBuffer> & buffer)
389+
const std::shared_ptr<ObservationBuffer> & buffer)
392390
{
393391
// project the laser into a point cloud
394392
sensor_msgs::msg::PointCloud2 cloud;
@@ -422,7 +420,7 @@ ObstacleLayer::laserScanCallback(
422420
void
423421
ObstacleLayer::laserScanValidInfCallback(
424422
sensor_msgs::msg::LaserScan::ConstSharedPtr raw_message,
425-
const std::shared_ptr<nav2_costmap_2d::ObservationBuffer> & buffer)
423+
const std::shared_ptr<ObservationBuffer> & buffer)
426424
{
427425
// Filter positive infinities ("Inf"s) to max_range.
428426
float epsilon = 0.0001; // a tenth of a millimeter
@@ -488,7 +486,7 @@ ObstacleLayer::updateBounds(
488486
useExtraBounds(min_x, min_y, max_x, max_y);
489487

490488
bool current = true;
491-
std::vector<Observation> observations, clearing_observations;
489+
std::vector<Observation::ConstSharedPtr> observations, clearing_observations;
492490

493491
// get the marking observations
494492
current = current && getMarkingObservations(observations);
@@ -500,15 +498,13 @@ ObstacleLayer::updateBounds(
500498
current_ = current;
501499

502500
// raytrace freespace
503-
for (unsigned int i = 0; i < clearing_observations.size(); ++i) {
504-
raytraceFreespace(clearing_observations[i], min_x, min_y, max_x, max_y);
501+
for (const auto & clearing_observation : clearing_observations) {
502+
raytraceFreespace(*clearing_observation, min_x, min_y, max_x, max_y);
505503
}
506504

507505
// place the new obstacles into a priority queue... each with a priority of zero to begin with
508-
for (std::vector<Observation>::const_iterator it = observations.begin();
509-
it != observations.end(); ++it)
510-
{
511-
const Observation & obs = *it;
506+
for (const auto & observation : observations) {
507+
const Observation & obs = *observation;
512508

513509
const sensor_msgs::msg::PointCloud2 & cloud = obs.cloud_;
514510

@@ -621,14 +617,15 @@ ObstacleLayer::updateCosts(
621617

622618
void
623619
ObstacleLayer::addStaticObservation(
624-
nav2_costmap_2d::Observation & obs,
620+
nav2_costmap_2d::Observation obs,
625621
bool marking, bool clearing)
626622
{
623+
const auto observation = Observation::make_shared(std::move(obs));
627624
if (marking) {
628-
static_marking_observations_.push_back(obs);
625+
static_marking_observations_.push_back(observation);
629626
}
630627
if (clearing) {
631-
static_clearing_observations_.push_back(obs);
628+
static_clearing_observations_.push_back(observation);
632629
}
633630
}
634631

@@ -644,15 +641,16 @@ ObstacleLayer::clearStaticObservations(bool marking, bool clearing)
644641
}
645642

646643
bool
647-
ObstacleLayer::getMarkingObservations(std::vector<Observation> & marking_observations) const
644+
ObstacleLayer::getMarkingObservations(
645+
std::vector<Observation::ConstSharedPtr> & marking_observations) const
648646
{
649647
bool current = true;
650648
// get the marking observations
651-
for (unsigned int i = 0; i < marking_buffers_.size(); ++i) {
652-
marking_buffers_[i]->lock();
653-
marking_buffers_[i]->getObservations(marking_observations);
654-
current = marking_buffers_[i]->isCurrent() && current;
655-
marking_buffers_[i]->unlock();
649+
for (const auto & marking_buffer : marking_buffers_) {
650+
marking_buffer->lock();
651+
marking_buffer->getObservations(marking_observations);
652+
current = marking_buffer->isCurrent() && current;
653+
marking_buffer->unlock();
656654
}
657655
marking_observations.insert(
658656
marking_observations.end(),
@@ -661,15 +659,16 @@ ObstacleLayer::getMarkingObservations(std::vector<Observation> & marking_observa
661659
}
662660

663661
bool
664-
ObstacleLayer::getClearingObservations(std::vector<Observation> & clearing_observations) const
662+
ObstacleLayer::getClearingObservations(
663+
std::vector<Observation::ConstSharedPtr> & clearing_observations) const
665664
{
666665
bool current = true;
667666
// get the clearing observations
668-
for (unsigned int i = 0; i < clearing_buffers_.size(); ++i) {
669-
clearing_buffers_[i]->lock();
670-
clearing_buffers_[i]->getObservations(clearing_observations);
671-
current = clearing_buffers_[i]->isCurrent() && current;
672-
clearing_buffers_[i]->unlock();
667+
for (const auto & clearing_buffer : clearing_buffers_) {
668+
clearing_buffer->lock();
669+
clearing_buffer->getObservations(clearing_observations);
670+
current = clearing_buffer->isCurrent() && current;
671+
clearing_buffer->unlock();
673672
}
674673
clearing_observations.insert(
675674
clearing_observations.end(),
@@ -821,10 +820,8 @@ ObstacleLayer::reset()
821820
void
822821
ObstacleLayer::resetBuffersLastUpdated()
823822
{
824-
for (unsigned int i = 0; i < observation_buffers_.size(); ++i) {
825-
if (observation_buffers_[i]) {
826-
observation_buffers_[i]->resetLastUpdated();
827-
}
823+
for (const auto & observation_buffer : observation_buffers_) {
824+
observation_buffer->resetLastUpdated();
828825
}
829826
}
830827

nav2_costmap_2d/plugins/voxel_layer.cpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ void VoxelLayer::updateBounds(
161161
useExtraBounds(min_x, min_y, max_x, max_y);
162162

163163
bool current = true;
164-
std::vector<Observation> observations, clearing_observations;
164+
std::vector<Observation::ConstSharedPtr> observations, clearing_observations;
165165

166166
// get the marking observations
167167
current = getMarkingObservations(observations) && current;
@@ -173,15 +173,13 @@ void VoxelLayer::updateBounds(
173173
current_ = current;
174174

175175
// raytrace freespace
176-
for (unsigned int i = 0; i < clearing_observations.size(); ++i) {
177-
raytraceFreespace(clearing_observations[i], min_x, min_y, max_x, max_y);
176+
for (const auto & clearing_observation : clearing_observations) {
177+
raytraceFreespace(*clearing_observation, min_x, min_y, max_x, max_y);
178178
}
179179

180180
// place the new obstacles into a priority queue... each with a priority of zero to begin with
181-
for (std::vector<Observation>::const_iterator it = observations.begin(); it != observations.end();
182-
++it)
183-
{
184-
const Observation & obs = *it;
181+
for (const auto & observation : observations) {
182+
const Observation & obs = *observation;
185183

186184
const sensor_msgs::msg::PointCloud2 & cloud = obs.cloud_;
187185

nav2_costmap_2d/src/observation_buffer.cpp

Lines changed: 21 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -76,22 +76,18 @@ ObservationBuffer::ObservationBuffer(
7676
last_updated_ = node->now();
7777
}
7878

79-
ObservationBuffer::~ObservationBuffer()
80-
{
81-
}
82-
8379
void ObservationBuffer::bufferCloud(const sensor_msgs::msg::PointCloud2 & cloud)
8480
{
8581
geometry_msgs::msg::PointStamped global_origin;
8682

87-
// create a new observation on the list to be populated
88-
observation_list_.push_front(Observation());
89-
9083
// check whether the origin frame has been set explicitly
9184
// or whether we should get it from the cloud
9285
std::string origin_frame = sensor_frame_ == "" ? cloud.header.frame_id : sensor_frame_;
9386

9487
try {
88+
// create a new observation to add to the list after being populated
89+
auto observation = Observation::make_shared();
90+
9591
// given these observations come from sensors...
9692
// we'll need to store the origin pt of the sensor
9793
geometry_msgs::msg::PointStamped local_origin;
@@ -101,14 +97,14 @@ void ObservationBuffer::bufferCloud(const sensor_msgs::msg::PointCloud2 & cloud)
10197
local_origin.point.y = 0;
10298
local_origin.point.z = 0;
10399
tf2_buffer_.transform(local_origin, global_origin, global_frame_, tf_tolerance_);
104-
tf2::convert(global_origin.point, observation_list_.front().origin_);
100+
tf2::convert(global_origin.point, observation->origin_);
105101

106102
// make sure to pass on the raytrace/obstacle range
107103
// of the observation buffer to the observations
108-
observation_list_.front().raytrace_max_range_ = raytrace_max_range_;
109-
observation_list_.front().raytrace_min_range_ = raytrace_min_range_;
110-
observation_list_.front().obstacle_max_range_ = obstacle_max_range_;
111-
observation_list_.front().obstacle_min_range_ = obstacle_min_range_;
104+
observation->raytrace_max_range_ = raytrace_max_range_;
105+
observation->raytrace_min_range_ = raytrace_min_range_;
106+
observation->obstacle_max_range_ = obstacle_max_range_;
107+
observation->obstacle_min_range_ = obstacle_min_range_;
112108

113109
sensor_msgs::msg::PointCloud2 global_frame_cloud;
114110

@@ -118,7 +114,7 @@ void ObservationBuffer::bufferCloud(const sensor_msgs::msg::PointCloud2 & cloud)
118114

119115
// now we need to remove observations from the cloud that are below
120116
// or above our height thresholds
121-
sensor_msgs::msg::PointCloud2 & observation_cloud = (observation_list_.front().cloud_);
117+
sensor_msgs::msg::PointCloud2 & observation_cloud = observation->cloud_;
122118
observation_cloud.height = global_frame_cloud.height;
123119
observation_cloud.width = global_frame_cloud.width;
124120
observation_cloud.fields = global_frame_cloud.fields;
@@ -153,9 +149,10 @@ void ObservationBuffer::bufferCloud(const sensor_msgs::msg::PointCloud2 & cloud)
153149
modifier.resize(point_count);
154150
observation_cloud.header.stamp = cloud.header.stamp;
155151
observation_cloud.header.frame_id = global_frame_cloud.header.frame_id;
152+
153+
observation_list_.push_front(std::move(observation));
156154
} catch (tf2::TransformException & ex) {
157155
// if an exception occurs, we need to remove the empty observation from the list
158-
observation_list_.pop_front();
159156
RCLCPP_ERROR(
160157
logger_,
161158
"TF Exception that should never happen for sensor frame: %s, cloud frame: %s, %s",
@@ -171,40 +168,27 @@ void ObservationBuffer::bufferCloud(const sensor_msgs::msg::PointCloud2 & cloud)
171168
purgeStaleObservations();
172169
}
173170

174-
// returns a copy of the observations
175-
void ObservationBuffer::getObservations(std::vector<Observation> & observations)
171+
// appends the observations from the buffer to the passed vector
172+
void ObservationBuffer::getObservations(std::vector<Observation::ConstSharedPtr> & observations)
176173
{
177174
// first... let's make sure that we don't have any stale observations
178175
purgeStaleObservations();
179176

180-
// now we'll just copy the observations for the caller
181-
std::list<Observation>::iterator obs_it;
182-
for (obs_it = observation_list_.begin(); obs_it != observation_list_.end(); ++obs_it) {
183-
observations.push_back(*obs_it);
184-
}
177+
// now we'll just copy the observation ptrs for the caller
178+
observations.insert(observations.end(), observation_list_.cbegin(), observation_list_.cend());
185179
}
186180

187181
void ObservationBuffer::purgeStaleObservations()
188182
{
189183
if (!observation_list_.empty()) {
190-
std::list<Observation>::iterator obs_it = observation_list_.begin();
191184
// if we're keeping observations for no time... then we'll only keep one observation
192185
if (observation_keep_time_ == rclcpp::Duration(0.0s)) {
193-
observation_list_.erase(++obs_it, observation_list_.end());
194-
return;
195-
}
196-
197-
// otherwise... we'll have to loop through the observations to see which ones are stale
198-
for (obs_it = observation_list_.begin(); obs_it != observation_list_.end(); ++obs_it) {
199-
Observation & obs = *obs_it;
200-
// check if the observation is out of date... and if it is,
201-
// remove it and those that follow from the list
202-
if ((clock_->now() - obs.cloud_->header.stamp) >
203-
observation_keep_time_)
204-
{
205-
observation_list_.erase(obs_it, observation_list_.end());
206-
return;
207-
}
186+
observation_list_.erase(std::next(observation_list_.begin()), observation_list_.end());
187+
} else {
188+
// otherwise remove all observations that are older then the keep time
189+
observation_list_.remove_if([now = clock_->now(), this](const auto observation){
190+
return (now - observation->cloud_.header.stamp) > observation_keep_time_;
191+
});
208192
}
209193
}
210194
}

nav2_costmap_2d/test/testing_helper.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include <memory>
2020
#include <string>
21+
#include <utility>
2122

2223
#include "rclcpp/rclcpp.hpp"
2324
#include "sensor_msgs/point_cloud2_iterator.hpp"
@@ -130,7 +131,7 @@ void addObservation(
130131
nav2_costmap_2d::Observation obs(std::move(p), std::move(cloud), obstacle_max_range,
131132
obstacle_min_range,
132133
raytrace_max_range, raytrace_min_range);
133-
olayer->addStaticObservation(obs, marking, clearing);
134+
olayer->addStaticObservation(std::move(obs), marking, clearing);
134135
}
135136

136137
void addInflationLayer(

0 commit comments

Comments
 (0)