Skip to content

Commit ebe9d7c

Browse files
authored
Refactor/observation buffer (#4890)
* Add benchmark for observation buffer Signed-off-by: Fabian König <[email protected]> * Apply rule of zero for Observation and do not use ptr for cloud Signed-off-by: Fabian König <[email protected]> * ObservationBuffer stores shared ptrs of observations to avoid copies when queried Signed-off-by: Fabian König <[email protected]> * Check for nullptr if *_buffers_ members are accessed Signed-off-by: Fabian König <[email protected]> --------- Signed-off-by: Fabian König <[email protected]>
1 parent 6a8560c commit ebe9d7c

File tree

13 files changed

+435
-150
lines changed

13 files changed

+435
-150
lines changed

nav2_costmap_2d/include/nav2_costmap_2d/observation.hpp

Lines changed: 15 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -32,52 +32,27 @@
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>
38+
#include <rclcpp/macros.hpp>
3739

3840
namespace nav2_costmap_2d
3941
{
4042

4143
/**
4244
* @brief Stores an observation in terms of a point cloud and the origin of the source
43-
* @note Tried to make members and constructor arguments const but the compiler would not accept the default
44-
* assignment operator for vector insertion!
4545
*/
4646
class Observation
4747
{
4848
public:
49-
/**
50-
* @brief Creates an empty observation
51-
*/
52-
Observation()
53-
: cloud_(new sensor_msgs::msg::PointCloud2()), obstacle_max_range_(0.0), obstacle_min_range_(0.0),
54-
raytrace_max_range_(0.0),
55-
raytrace_min_range_(0.0)
56-
{
57-
}
58-
/**
59-
* @brief A destructor
60-
*/
61-
virtual ~Observation()
62-
{
63-
delete cloud_;
64-
}
49+
RCLCPP_SMART_PTR_DEFINITIONS(Observation)
6550

6651
/**
67-
* @brief Copy assignment operator
68-
* @param obs The observation to copy
52+
* @brief Creates an empty observation
6953
*/
70-
Observation & operator=(const Observation & obs)
71-
{
72-
origin_ = obs.origin_;
73-
cloud_ = new sensor_msgs::msg::PointCloud2(*(obs.cloud_));
74-
obstacle_max_range_ = obs.obstacle_max_range_;
75-
obstacle_min_range_ = obs.obstacle_min_range_;
76-
raytrace_max_range_ = obs.raytrace_max_range_;
77-
raytrace_min_range_ = obs.raytrace_min_range_;
54+
Observation() = default;
7855

79-
return *this;
80-
}
8156

8257
/**
8358
* @brief Creates an observation from an origin point and a point cloud
@@ -89,28 +64,16 @@ class Observation
8964
* @param raytrace_min_range The range from which an observation should be able to clear via raytracing
9065
*/
9166
Observation(
92-
geometry_msgs::msg::Point & origin, const sensor_msgs::msg::PointCloud2 & cloud,
67+
geometry_msgs::msg::Point origin, sensor_msgs::msg::PointCloud2 cloud,
9368
double obstacle_max_range, double obstacle_min_range, double raytrace_max_range,
9469
double raytrace_min_range)
95-
: origin_(origin), cloud_(new sensor_msgs::msg::PointCloud2(cloud)),
70+
: origin_(std::move(origin)), cloud_(std::move(cloud)),
9671
obstacle_max_range_(obstacle_max_range), obstacle_min_range_(obstacle_min_range),
9772
raytrace_max_range_(raytrace_max_range), raytrace_min_range_(
9873
raytrace_min_range)
9974
{
10075
}
10176

102-
/**
103-
* @brief Copy constructor
104-
* @param obs The observation to copy
105-
*/
106-
Observation(const Observation & obs)
107-
: origin_(obs.origin_), cloud_(new sensor_msgs::msg::PointCloud2(*(obs.cloud_))),
108-
obstacle_max_range_(obs.obstacle_max_range_), obstacle_min_range_(obs.obstacle_min_range_),
109-
raytrace_max_range_(obs.raytrace_max_range_),
110-
raytrace_min_range_(obs.raytrace_min_range_)
111-
{
112-
}
113-
11477
/**
11578
* @brief Creates an observation from a point cloud
11679
* @param cloud The point cloud of the observation
@@ -120,15 +83,17 @@ class Observation
12083
Observation(
12184
const sensor_msgs::msg::PointCloud2 & cloud, double obstacle_max_range,
12285
double obstacle_min_range)
123-
: cloud_(new sensor_msgs::msg::PointCloud2(cloud)), obstacle_max_range_(obstacle_max_range),
124-
obstacle_min_range_(obstacle_min_range),
125-
raytrace_max_range_(0.0), raytrace_min_range_(0.0)
86+
: cloud_(std::move(cloud)), obstacle_max_range_(obstacle_max_range),
87+
obstacle_min_range_(obstacle_min_range)
12688
{
12789
}
12890

129-
geometry_msgs::msg::Point origin_;
130-
sensor_msgs::msg::PointCloud2 * cloud_;
131-
double obstacle_max_range_, obstacle_min_range_, raytrace_max_range_, raytrace_min_range_;
91+
geometry_msgs::msg::Point origin_{};
92+
sensor_msgs::msg::PointCloud2 cloud_{};
93+
double obstacle_max_range_{0.};
94+
double obstacle_min_range_{0.};
95+
double raytrace_max_range_{0.};
96+
double raytrace_min_range_{0.};
13297
};
13398

13499
} // namespace nav2_costmap_2d

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
@@ -175,7 +175,7 @@ class ObstacleLayer : public CostmapLayer
175175
const std::shared_ptr<nav2_costmap_2d::ObservationBuffer> & buffer);
176176

177177
// for testing purposes
178-
void addStaticObservation(nav2_costmap_2d::Observation & obs, bool marking, bool clearing);
178+
void addStaticObservation(nav2_costmap_2d::Observation obs, bool marking, bool clearing);
179179
void clearStaticObservations(bool marking, bool clearing);
180180

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

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

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

258258
// Used only for testing purposes
259-
std::vector<nav2_costmap_2d::Observation> static_clearing_observations_;
260-
std::vector<nav2_costmap_2d::Observation> static_marking_observations_;
259+
std::vector<nav2_costmap_2d::Observation::ConstSharedPtr> static_clearing_observations_;
260+
std::vector<nav2_costmap_2d::Observation::ConstSharedPtr> static_marking_observations_;
261261

262262
bool rolling_window_;
263263
bool was_reset_;

nav2_costmap_2d/package.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
<test_depend>ament_lint_auto</test_depend>
5050
<test_depend>nav2_map_server</test_depend>
5151
<test_depend>ament_cmake_gtest</test_depend>
52+
<test_depend>ament_cmake_google_benchmark</test_depend>
5253
<test_depend>launch</test_depend>
5354
<test_depend>launch_testing</test_depend>
5455
<test_depend>nav2_lifecycle_manager</test_depend>

nav2_costmap_2d/plugins/obstacle_layer.cpp

Lines changed: 37 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -206,15 +206,13 @@ void ObstacleLayer::onInitialize()
206206

207207
// create an observation buffer
208208
observation_buffers_.push_back(
209-
std::shared_ptr<ObservationBuffer
210-
>(
211-
new ObservationBuffer(
212-
node, topic, observation_keep_time, expected_update_rate,
209+
std::make_shared<ObservationBuffer>(node, topic, observation_keep_time,
210+
expected_update_rate,
213211
min_obstacle_height,
214212
max_obstacle_height, obstacle_max_range, obstacle_min_range, raytrace_max_range,
215213
raytrace_min_range, *tf_,
216214
global_frame_,
217-
sensor_frame, tf2::durationFromSec(transform_tolerance))));
215+
sensor_frame, tf2::durationFromSec(transform_tolerance)));
218216

219217
// check if we'll add this buffer to our marking observation buffers
220218
if (marking) {
@@ -399,7 +397,7 @@ ObstacleLayer::dynamicParametersCallback(
399397
void
400398
ObstacleLayer::laserScanCallback(
401399
sensor_msgs::msg::LaserScan::ConstSharedPtr message,
402-
const std::shared_ptr<nav2_costmap_2d::ObservationBuffer> & buffer)
400+
const std::shared_ptr<ObservationBuffer> & buffer)
403401
{
404402
// project the laser into a point cloud
405403
sensor_msgs::msg::PointCloud2 cloud;
@@ -433,7 +431,7 @@ ObstacleLayer::laserScanCallback(
433431
void
434432
ObstacleLayer::laserScanValidInfCallback(
435433
sensor_msgs::msg::LaserScan::ConstSharedPtr raw_message,
436-
const std::shared_ptr<nav2_costmap_2d::ObservationBuffer> & buffer)
434+
const std::shared_ptr<ObservationBuffer> & buffer)
437435
{
438436
// Filter positive infinities ("Inf"s) to max_range.
439437
float epsilon = 0.0001; // a tenth of a millimeter
@@ -499,7 +497,7 @@ ObstacleLayer::updateBounds(
499497
useExtraBounds(min_x, min_y, max_x, max_y);
500498

501499
bool current = true;
502-
std::vector<Observation> observations, clearing_observations;
500+
std::vector<Observation::ConstSharedPtr> observations, clearing_observations;
503501

504502
// get the marking observations
505503
current = current && getMarkingObservations(observations);
@@ -511,17 +509,15 @@ ObstacleLayer::updateBounds(
511509
current_ = current;
512510

513511
// raytrace freespace
514-
for (unsigned int i = 0; i < clearing_observations.size(); ++i) {
515-
raytraceFreespace(clearing_observations[i], min_x, min_y, max_x, max_y);
512+
for (const auto & clearing_observation : clearing_observations) {
513+
raytraceFreespace(*clearing_observation, min_x, min_y, max_x, max_y);
516514
}
517515

518516
// place the new obstacles into a priority queue... each with a priority of zero to begin with
519-
for (std::vector<Observation>::const_iterator it = observations.begin();
520-
it != observations.end(); ++it)
521-
{
522-
const Observation & obs = *it;
517+
for (const auto & observation : observations) {
518+
const Observation & obs = *observation;
523519

524-
const sensor_msgs::msg::PointCloud2 & cloud = *(obs.cloud_);
520+
const sensor_msgs::msg::PointCloud2 & cloud = obs.cloud_;
525521

526522
double sq_obstacle_max_range = obs.obstacle_max_range_ * obs.obstacle_max_range_;
527523
double sq_obstacle_min_range = obs.obstacle_min_range_ * obs.obstacle_min_range_;
@@ -632,14 +628,15 @@ ObstacleLayer::updateCosts(
632628

633629
void
634630
ObstacleLayer::addStaticObservation(
635-
nav2_costmap_2d::Observation & obs,
631+
nav2_costmap_2d::Observation obs,
636632
bool marking, bool clearing)
637633
{
634+
const auto observation = Observation::make_shared(std::move(obs));
638635
if (marking) {
639-
static_marking_observations_.push_back(obs);
636+
static_marking_observations_.push_back(observation);
640637
}
641638
if (clearing) {
642-
static_clearing_observations_.push_back(obs);
639+
static_clearing_observations_.push_back(observation);
643640
}
644641
}
645642

@@ -655,15 +652,18 @@ ObstacleLayer::clearStaticObservations(bool marking, bool clearing)
655652
}
656653

657654
bool
658-
ObstacleLayer::getMarkingObservations(std::vector<Observation> & marking_observations) const
655+
ObstacleLayer::getMarkingObservations(
656+
std::vector<Observation::ConstSharedPtr> & marking_observations) const
659657
{
660658
bool current = true;
661659
// get the marking observations
662-
for (unsigned int i = 0; i < marking_buffers_.size(); ++i) {
663-
marking_buffers_[i]->lock();
664-
marking_buffers_[i]->getObservations(marking_observations);
665-
current = marking_buffers_[i]->isCurrent() && current;
666-
marking_buffers_[i]->unlock();
660+
for (const auto & marking_buffer : marking_buffers_) {
661+
if (marking_buffer) {
662+
marking_buffer->lock();
663+
marking_buffer->getObservations(marking_observations);
664+
current = marking_buffer->isCurrent() && current;
665+
marking_buffer->unlock();
666+
}
667667
}
668668
marking_observations.insert(
669669
marking_observations.end(),
@@ -672,15 +672,18 @@ ObstacleLayer::getMarkingObservations(std::vector<Observation> & marking_observa
672672
}
673673

674674
bool
675-
ObstacleLayer::getClearingObservations(std::vector<Observation> & clearing_observations) const
675+
ObstacleLayer::getClearingObservations(
676+
std::vector<Observation::ConstSharedPtr> & clearing_observations) const
676677
{
677678
bool current = true;
678679
// get the clearing observations
679-
for (unsigned int i = 0; i < clearing_buffers_.size(); ++i) {
680-
clearing_buffers_[i]->lock();
681-
clearing_buffers_[i]->getObservations(clearing_observations);
682-
current = clearing_buffers_[i]->isCurrent() && current;
683-
clearing_buffers_[i]->unlock();
680+
for (const auto & clearing_buffer : clearing_buffers_) {
681+
if (clearing_buffer) {
682+
clearing_buffer->lock();
683+
clearing_buffer->getObservations(clearing_observations);
684+
current = clearing_buffer->isCurrent() && current;
685+
clearing_buffer->unlock();
686+
}
684687
}
685688
clearing_observations.insert(
686689
clearing_observations.end(),
@@ -697,7 +700,7 @@ ObstacleLayer::raytraceFreespace(
697700
{
698701
double ox = clearing_observation.origin_.x;
699702
double oy = clearing_observation.origin_.y;
700-
const sensor_msgs::msg::PointCloud2 & cloud = *(clearing_observation.cloud_);
703+
const sensor_msgs::msg::PointCloud2 & cloud = clearing_observation.cloud_;
701704

702705
// get the map coordinates of the origin of the sensor
703706
unsigned int x0, y0;
@@ -833,9 +836,9 @@ ObstacleLayer::reset()
833836
void
834837
ObstacleLayer::resetBuffersLastUpdated()
835838
{
836-
for (unsigned int i = 0; i < observation_buffers_.size(); ++i) {
837-
if (observation_buffers_[i]) {
838-
observation_buffers_[i]->resetLastUpdated();
839+
for (const auto & observation_buffer : observation_buffers_) {
840+
if (observation_buffer) {
841+
observation_buffer->resetLastUpdated();
839842
}
840843
}
841844
}

0 commit comments

Comments
 (0)