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

Add ability to publish layers of the costmap #3254

Merged
merged 45 commits into from
Dec 8, 2022
Merged
Show file tree
Hide file tree
Changes from 41 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
7a5b546
publish layers of costmap
Oct 24, 2022
0f2e97b
lint fix
Oct 24, 2022
7d950eb
lint round 2 :)
Oct 24, 2022
82481ab
code review
Oct 26, 2022
447f80f
remove isPublishable
Nov 2, 2022
11459a1
lint
Nov 4, 2022
4a222d6
test running
Nov 7, 2022
0285d20
rough structure complete
Nov 7, 2022
c52243e
completed test
Nov 15, 2022
f184acf
lint
Nov 15, 2022
b09ce66
code review
Nov 15, 2022
a663d58
CI
Nov 16, 2022
ce48a59
CI
Nov 16, 2022
b0dab49
linting
Nov 21, 2022
f3ab862
completed pub test
Nov 30, 2022
c2f9f0b
CostmapLayer::matchSize may be executed concurrently (#3250)
Cryst4L9527 Oct 24, 2022
7340017
Fix typo (#3262)
woawo1213 Nov 1, 2022
15f5800
Adding new Nav2 Smoother: Savitzky-Golay Smoother (#3264)
SteveMacenski Nov 3, 2022
be85e52
refactoring RPP a bit for cleanliness on way to ROSCon (#3265)
SteveMacenski Nov 3, 2022
c3b5cce
exceptions for compute path through poses (#3248)
jwallace42 Nov 3, 2022
d042786
Reclaim Our CI Coverage from the Lords of Painful Subtle Regressions …
SteveMacenski Nov 3, 2022
6d66c9d
Added Line Iterator (#3197)
afifswaidan Nov 7, 2022
ee7e505
Use SetParameter Launch API to set the yaml filename for map_server (…
stevedanomodolor Nov 7, 2022
52a31c6
adding reconfigure test to thetastar (#3275)
padhupradheep Nov 9, 2022
e528ccc
Check for range_max of laserscan in updateFilter to avoid a implicit …
Cryst4L9527 Nov 10, 2022
3f8011f
BT Service Node to throw if service was not available in time (#3256)
guilyx Nov 11, 2022
ead132a
remove exec_depend on behaviortree_cpp_v3 (#3279)
Aposhian Nov 11, 2022
7335d6b
add parameterized refinement recursion numbers in Smac Planner Smooth…
SteveMacenski Nov 15, 2022
65a9e4f
Add allow_unknown parameter to theta star planner (#3286)
pepisg Nov 16, 2022
eb2c779
Include test cases waypoint follwer (#3288)
stevedanomodolor Nov 16, 2022
06cac21
Dynamically changing polygons support (#3245)
AlexeyMerzlyakov Nov 17, 2022
bc95038
adding getCostScalingFactor (#3290)
SteveMacenski Nov 17, 2022
6b221b7
Implemented smoother selector bt node (#3283)
owen7900 Nov 18, 2022
ebf079e
Pipe error codes (#3251)
jwallace42 Nov 18, 2022
ba3d647
Solve bug when CostmapInfoServer is reactivated (#3292)
MartiBolet Nov 20, 2022
76314ac
Smoothness metrics update (#3294)
AlexeyMerzlyakov Nov 20, 2022
a7a77fc
preempt/cancel test for time behavior, spin pluguin (#3301)
stevedanomodolor Nov 29, 2022
3152214
lint fix
Oct 24, 2022
6f13a90
Merge branch 'main' into publish_layers
Nov 30, 2022
83376aa
clean up test
Dec 2, 2022
cdaa851
lint
Dec 2, 2022
0cad731
cleaned up test
Dec 7, 2022
e552f3e
Merge branch 'main' into publish_layers
Dec 7, 2022
539db41
update
Dec 7, 2022
1a05397
revert Cmake
Dec 8, 2022
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
4 changes: 3 additions & 1 deletion nav2_costmap_2d/include/nav2_costmap_2d/costmap_2d_ros.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,9 @@ class Costmap2DROS : public nav2_util::LifecycleNode
// Publishers and subscribers
rclcpp_lifecycle::LifecyclePublisher<geometry_msgs::msg::PolygonStamped>::SharedPtr
footprint_pub_;
std::unique_ptr<Costmap2DPublisher> costmap_publisher_{nullptr};
std::unique_ptr<Costmap2DPublisher> costmap_publisher_;

std::vector<std::unique_ptr<Costmap2DPublisher>> layer_publishers_;

rclcpp::Subscription<geometry_msgs::msg::Polygon>::SharedPtr footprint_sub_;
rclcpp::Subscription<rcl_interfaces::msg::ParameterEvent>::SharedPtr parameter_sub_;
Expand Down
2 changes: 1 addition & 1 deletion nav2_costmap_2d/src/costmap_2d_publisher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,8 @@ void Costmap2DPublisher::publishCostmap()
prepareCostmap();
costmap_raw_pub_->publish(std::move(costmap_raw_));
}
float resolution = costmap_->getResolution();

float resolution = costmap_->getResolution();
if (always_send_full_costmap_ || grid_resolution != resolution ||
grid_width != costmap_->getSizeInCellsX() ||
grid_height != costmap_->getSizeInCellsY() ||
Expand Down
45 changes: 41 additions & 4 deletions nav2_costmap_2d/src/costmap_2d_ros.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,20 @@ Costmap2DROS::on_configure(const rclcpp_lifecycle::State & /*state*/)
layered_costmap_->getCostmap(), global_frame_,
"costmap", always_send_full_costmap_);

auto layers = layered_costmap_->getPlugins();
AlexeyMerzlyakov marked this conversation as resolved.
Show resolved Hide resolved

for (auto & layer : *layers) {
auto costmap_layer = std::dynamic_pointer_cast<CostmapLayer>(layer);
if (costmap_layer != nullptr) {
layer_publishers_.emplace_back(
std::make_unique<Costmap2DPublisher>(
shared_from_this(),
costmap_layer.get(), global_frame_,
layer->getName(), always_send_full_costmap_)
);
}
}

// Set the footprint
if (use_radius_) {
setRobotFootprint(makeFootprintFromRadius(robot_radius_));
Expand All @@ -233,8 +247,12 @@ Costmap2DROS::on_activate(const rclcpp_lifecycle::State & /*state*/)
{
RCLCPP_INFO(get_logger(), "Activating");

costmap_publisher_->on_activate();
footprint_pub_->on_activate();
costmap_publisher_->on_activate();

for (auto & layer_pub : layer_publishers_) {
layer_pub->on_activate();
}

// First, make sure that the transform between the robot base frame
// and the global frame is available
Expand Down Expand Up @@ -280,8 +298,13 @@ Costmap2DROS::on_deactivate(const rclcpp_lifecycle::State & /*state*/)
RCLCPP_INFO(get_logger(), "Deactivating");

dyn_params_handler.reset();
costmap_publisher_->on_deactivate();

footprint_pub_->on_deactivate();
costmap_publisher_->on_deactivate();

for (auto & layer_pub : layer_publishers_) {
layer_pub->on_deactivate();
}

stop();

Expand All @@ -297,6 +320,13 @@ Costmap2DROS::on_cleanup(const rclcpp_lifecycle::State & /*state*/)
{
RCLCPP_INFO(get_logger(), "Cleaning up");

costmap_publisher_.reset();
clear_costmap_service_.reset();

for (auto & layer_pub : layer_publishers_) {
layer_pub.reset();
}

layered_costmap_.reset();

tf_listener_.reset();
Expand All @@ -305,8 +335,6 @@ Costmap2DROS::on_cleanup(const rclcpp_lifecycle::State & /*state*/)
footprint_sub_.reset();
footprint_pub_.reset();

costmap_publisher_.reset();
clear_costmap_service_.reset();

executor_thread_.reset();
return nav2_util::CallbackReturn::SUCCESS;
Expand Down Expand Up @@ -446,12 +474,21 @@ Costmap2DROS::mapUpdateLoop(double frequency)
layered_costmap_->getBounds(&x0, &xn, &y0, &yn);
costmap_publisher_->updateBounds(x0, xn, y0, yn);

for (auto & layer_pub : layer_publishers_) {
layer_pub->updateBounds(x0, xn, y0, yn);
}

auto current_time = now();
if ((last_publish_ + publish_cycle_ < current_time) || // publish_cycle_ is due
(current_time < last_publish_)) // time has moved backwards, probably due to a switch to sim_time // NOLINT
{
RCLCPP_DEBUG(get_logger(), "Publish costmap at %s", name_.c_str());
costmap_publisher_->publishCostmap();

for (auto & layer_pub : layer_publishers_) {
layer_pub->publishCostmap();
}

last_publish_ = current_time;
}
}
Expand Down
22 changes: 22 additions & 0 deletions nav2_costmap_2d/test/integration/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,18 @@ target_link_libraries(dyn_params_tests
nav2_costmap_2d_core
)

ament_add_gtest_executable(test_costmap_publisher_exec
test_costmap_2d_publisher.cpp
)
ament_target_dependencies(test_costmap_publisher_exec
${dependencies}
)
target_link_libraries(test_costmap_publisher_exec
nav2_costmap_2d_core
nav2_costmap_2d_client
layers
)

ament_add_test(test_collision_checker
GENERATE_RESULT_FOR_RETURN_CODE_ZERO
COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/costmap_tests_launch.py"
Expand Down Expand Up @@ -114,6 +126,16 @@ ament_add_test(range_tests
TEST_EXECUTABLE=$<TARGET_FILE:range_tests_exec>
)

ament_add_test(test_costmap_publisher_exec
GENERATE_RESULT_FOR_RETURN_CODE_ZERO
COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/costmap_tests_launch.py"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
ENV
TEST_MAP=${TEST_MAP_DIR}/TenByTen.yaml
TEST_LAUNCH_DIR=${TEST_LAUNCH_DIR}
TEST_EXECUTABLE=$<TARGET_FILE:test_costmap_publisher_exec>
)

## TODO(bpwilcox): this test (I believe) is intended to be launched with the simple_driving_test.xml,
## which has a dependency on rosbag playback
# ament_add_gtest_executable(costmap_tester
Expand Down
16 changes: 16 additions & 0 deletions nav2_costmap_2d/test/integration/costmap_tests_launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,20 @@ def main(argv=sys.argv[1:]):
launchFile = os.path.join(os.getenv('TEST_LAUNCH_DIR'), 'costmap_map_server.launch.py')
testExecutable = os.getenv('TEST_EXECUTABLE')

map_to_odom = launch_ros.actions.Node(
package='tf2_ros',
executable='static_transform_publisher',
output='screen',
arguments=['0', '0', '0', '0', '0', '0', 'map', 'odom']
)

odom_to_base_link = launch_ros.actions.Node(
package='tf2_ros',
executable='static_transform_publisher',
output='screen',
arguments=['0', '0', '0', '0', '0', '0', 'odom', 'base_link']
)

lifecycle_manager = launch_ros.actions.Node(
package='nav2_lifecycle_manager',
executable='lifecycle_manager',
Expand All @@ -39,6 +53,8 @@ def main(argv=sys.argv[1:]):

ld = LaunchDescription([
IncludeLaunchDescription(PythonLaunchDescriptionSource([launchFile])),
map_to_odom,
odom_to_base_link,
lifecycle_manager
])

Expand Down
151 changes: 151 additions & 0 deletions nav2_costmap_2d/test/integration/test_costmap_2d_publisher.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
// Copyright (c) 2022 Joshua Wallace
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License. Reserved.

#include <gtest/gtest.h>

#include <future>

#include "nav2_costmap_2d/costmap_2d.hpp"
#include "nav2_costmap_2d/costmap_subscriber.hpp"
#include "nav2_costmap_2d/cost_values.hpp"
#include "tf2_ros/transform_listener.h"
#include "nav2_costmap_2d/costmap_2d_ros.hpp"

class RclCppFixture
{
public:
RclCppFixture() {rclcpp::init(0, nullptr);}
~RclCppFixture() {rclcpp::shutdown();}
};
RclCppFixture g_rclcppfixture;

class TestCostmap2dPublisher : public nav2_util::LifecycleNode
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this a subscriber mostly?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename to TestCostmap2DSubscriber

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are testing the that the costmap_2d_ros_ object publishes the layer of the costmap. Maybe a better name would be TestCostmap2DLayerPub?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its not publishing anything though, especially after costmap_ros_ moves out of the object. It only contains a subscription.

{
public:
explicit TestCostmap2dPublisher(const std::string & name)
: LifecycleNode(name)
{
RCLCPP_INFO(get_logger(), "Constructing");
}

~TestCostmap2dPublisher() override = default;

nav2_util::CallbackReturn
on_configure(const rclcpp_lifecycle::State &) override
{
RCLCPP_INFO(get_logger(), "Configuring");

callback_group_ = create_callback_group(
rclcpp::CallbackGroupType::MutuallyExclusive, false);

rclcpp::SubscriptionOptions sub_option;
sub_option.callback_group = callback_group_;

std::string topic_name = "/dummy_costmap/static_layer_raw";
SteveMacenski marked this conversation as resolved.
Show resolved Hide resolved
costmap_sub_ = this->create_subscription<nav2_msgs::msg::Costmap>(
topic_name,
rclcpp::QoS(rclcpp::KeepLast(1)).transient_local().reliable(),
std::bind(&TestCostmap2dPublisher::costmapCallback, this, std::placeholders::_1),
sub_option);

executor_ = std::make_shared<rclcpp::executors::SingleThreadedExecutor>();
executor_->add_callback_group(callback_group_, get_node_base_interface());
executor_thread_ = std::make_unique<nav2_util::NodeThread>(executor_);

costmap_ros_ = std::make_shared<nav2_costmap_2d::Costmap2DROS>(
"dummy_costmap",
std::string{get_namespace()},
"dummy_costmap",
get_parameter("use_sim_time").as_bool());
costmap_thread_ = std::make_unique<nav2_util::NodeThread>(costmap_ros_);

costmap_ros_->configure();

return nav2_util::CallbackReturn::SUCCESS;
}

nav2_util::CallbackReturn
on_activate(const rclcpp_lifecycle::State &) override
{
RCLCPP_INFO(get_logger(), "Activating");
costmap_ros_->activate();
return nav2_util::CallbackReturn::SUCCESS;
}

nav2_util::CallbackReturn
on_deactivate(const rclcpp_lifecycle::State &) override
{
RCLCPP_INFO(get_logger(), "Deactivating");
costmap_ros_->deactivate();
return nav2_util::CallbackReturn::SUCCESS;
}

nav2_util::CallbackReturn
on_cleanup(const rclcpp_lifecycle::State &) override
{
executor_thread_.reset();
costmap_thread_.reset();
costmap_ros_->deactivate();
return nav2_util::CallbackReturn::SUCCESS;
}

void costmapCallback(const nav2_msgs::msg::Costmap::SharedPtr costmap)
{
promise_.set_value(costmap);
}

rclcpp::Subscription<nav2_msgs::msg::Costmap>::SharedPtr costmap_sub_;

rclcpp::CallbackGroup::SharedPtr callback_group_;
rclcpp::executors::SingleThreadedExecutor::SharedPtr executor_;
std::unique_ptr<nav2_util::NodeThread> executor_thread_;
std::promise<nav2_msgs::msg::Costmap::SharedPtr> promise_;

std::shared_ptr<nav2_costmap_2d::Costmap2DROS> costmap_ros_;
std::unique_ptr<nav2_util::NodeThread> costmap_thread_;
};

class TestNode : public ::testing::Test
{
public:
TestNode()
{
costmap_publisher_ = std::make_shared<TestCostmap2dPublisher>("test_costmap_publisher");
costmap_publisher_->on_configure(costmap_publisher_->get_current_state());
costmap_publisher_->on_activate(costmap_publisher_->get_current_state());
}

~TestNode() override
{
costmap_publisher_->on_deactivate(costmap_publisher_->get_current_state());
costmap_publisher_->on_cleanup(costmap_publisher_->get_current_state());
}

protected:
std::shared_ptr<TestCostmap2dPublisher> costmap_publisher_;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move the costmap 2d ros object into the TestNode. Its quite confusing to have it in the publisher fixture. I think that separates your intent much more cleanly.

};

TEST_F(TestNode, costmap_pub_test)
SteveMacenski marked this conversation as resolved.
Show resolved Hide resolved
{
auto future = costmap_publisher_->promise_.get_future();
auto status = future.wait_for(std::chrono::seconds(5));
EXPECT_TRUE(status == std::future_status::ready);

auto costmap_raw = future.get();

// Check that the first row is free space
for (int i = 0; i < 10; ++i) {
EXPECT_EQ(costmap_raw->data[0], nav2_costmap_2d::FREE_SPACE);
}
}