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

Introduce rclcpp_components to implement composition #665

Merged
merged 14 commits into from
Apr 4, 2019
Merged
9 changes: 1 addition & 8 deletions rclcpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -432,14 +432,7 @@ if(BUILD_TESTING)
endif()
endif()

ament_package(
CONFIG_EXTRAS rclcpp-extras.cmake
)

install(
DIRECTORY cmake
DESTINATION share/${PROJECT_NAME}
)
ament_package()

install(
DIRECTORY include/ ${CMAKE_CURRENT_BINARY_DIR}/include/
Expand Down
26 changes: 0 additions & 26 deletions rclcpp/cmake/rclcpp_create_node_main.cmake

This file was deleted.

82 changes: 82 additions & 0 deletions rclcpp_components/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
cmake_minimum_required(VERSION 3.5)

project(rclcpp_components)

# Default to C++14
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 14)
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()

find_package(ament_cmake_ros REQUIRED)
find_package(ament_index_cpp REQUIRED)
find_package(class_loader REQUIRED)
find_package(composition_interfaces REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rcpputils REQUIRED)

include_directories(include)

add_executable(
component_container
src/component_container.cpp
src/component_manager.cpp
)

ament_target_dependencies(component_container
"ament_index_cpp"
"class_loader"
"composition_interfaces"
"rclcpp"
"rcpputils"
)

add_executable(
component_container_mt
src/component_container_mt.cpp
src/component_manager.cpp
wjwwood marked this conversation as resolved.
Show resolved Hide resolved
)

ament_target_dependencies(component_container_mt
"ament_index_cpp"
"class_loader"
"composition_interfaces"
"rclcpp"
"rcpputils"
)

if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
target_link_libraries(component_container "stdc++fs")
target_link_libraries(component_container_mt "stdc++fs")
endif()

if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
ament_lint_auto_find_test_dependencies()
endif()

# Install executables
install(
TARGETS component_container component_container_mt
RUNTIME DESTINATION lib/${PROJECT_NAME}
)

# Install include directories
install(
DIRECTORY include/
DESTINATION include
)

# Install cmake
install(
DIRECTORY cmake
DESTINATION share/${PROJECT_NAME}
)

# specific order: dependents before dependencies
ament_export_include_directories(include)
ament_export_dependencies(class_loader)
ament_export_dependencies(rclcpp)
ament_package(CONFIG_EXTRAS rclcpp_components-extras.cmake)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2016 Open Source Robotics Foundation, Inc.
# Copyright 2019 Open Source Robotics Foundation, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand All @@ -14,4 +14,5 @@

# register node plugins
ament_index_register_resource(
"node_plugin" CONTENT "${_RCLCPP__NODE_PLUGINS}")
"rclcpp_components" CONTENT "${_RCLCPP_COMPONENTS__NODES}")

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2016 Open Source Robotics Foundation, Inc.
# Copyright 2019 Open Source Robotics Foundation, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand All @@ -13,38 +13,38 @@
# limitations under the License.

#
# Register a node plugin with the ament resource index.
# Register an rclcpp component with the ament resource index.
#
# The passed library can contain multiple plugins extending the node interface.
# The passed library can contain multiple nodes each registered via macro.
#
# :param target: the shared library target
# :type target: string
# :param ARGN: the unique plugin names being exported using class_loader
# :type ARGN: list of strings
#
macro(rclcpp_register_node_plugins target)
macro(rclcpp_components_register_nodes target)
if(NOT TARGET ${target})
message(
FATAL_ERROR
"rclcpp_register_node_plugins() first argument "
"rclcpp_components_register_nodes() first argument "
"'${target}' is not a target")
endif()
get_target_property(_target_type ${target} TYPE)
if(NOT _target_type STREQUAL "SHARED_LIBRARY")
message(
FATAL_ERROR
"rclcpp_register_node_plugins() first argument "
"rclcpp_components_register_nodes() first argument "
"'${target}' is not a shared library target")
endif()

if(${ARGC} GREATER 0)
_rclcpp_register_package_hook()
_rclcpp_components_register_package_hook()
set(_unique_names)
foreach(_arg ${ARGN})
if(_arg IN_LIST _unique_names)
message(
FATAL_ERROR
"rclcpp_register_node_plugins() the plugin names "
"rclcpp_components_register_nodes() the plugin names "
"must be unique (multiple '${_arg}')")
endif()
list(APPEND _unique_names "${_arg}")
Expand All @@ -54,8 +54,9 @@ macro(rclcpp_register_node_plugins target)
else()
set(_path "lib")
endif()
set(_RCLCPP__NODE_PLUGINS
"${_RCLCPP__NODE_PLUGINS}${_arg};${_path}/$<TARGET_FILE_NAME:${target}>\n")
set(_RCLCPP_COMPONENTS__NODES
"${_RCLCPP_COMPONENTS__NODES}${_arg};${_path}/$<TARGET_FILE_NAME:${target}>\n")
endforeach()
endif()
endmacro()

46 changes: 46 additions & 0 deletions rclcpp_components/include/rclcpp_components/node_factory.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright 2019 Open Source Robotics Foundation, Inc.
//
// 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.

#ifndef RCLCPP_COMPONENTS__NODE_FACTORY_HPP__
#define RCLCPP_COMPONENTS__NODE_FACTORY_HPP__

#include "rclcpp_components/node_instance_wrapper.hpp"

namespace rclcpp_components
{

/// The NodeFactory interface is used by the class loader to instantiate components.
/**
* The NodeFactory interface serves two purposes:
* * It allows for classes not derived from `rclcpp::Node` to be used as components.
* * It derived constructors to be called when components are loaded.
wjwwood marked this conversation as resolved.
Show resolved Hide resolved
*/
class NodeFactory
wjwwood marked this conversation as resolved.
Show resolved Hide resolved
{
public:
NodeFactory() = default;

virtual ~NodeFactory() = default;

/// Create an instance of a component
/**
* \param[in] options Additional options used in the construction of the component.
*/
virtual
NodeInstanceWrapper
create_node_instance(const rclcpp::NodeOptions & options) = 0;
};
} // namespace rclcpp_components

#endif // RCLCPP_COMPONENTS__NODE_FACTORY_HPP__
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright 2019 Open Source Robotics Foundation, Inc.
//
// 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.

#ifndef RCLCPP_COMPONENTS__NODE_FACTORY_TEMPLATE_HPP__
#define RCLCPP_COMPONENTS__NODE_FACTORY_TEMPLATE_HPP__

#include <functional>
#include <memory>

#include "rclcpp_components/node_factory.hpp"

namespace rclcpp_components
{

/// NodeFactoryTemplate is a convenience class for instantiating components.
/**
* The NodeFactoryTemplate class can be used to easily proved the NodeFactory interface for
wjwwood marked this conversation as resolved.
Show resolved Hide resolved
* components that implement a single-argument constructor and `get_node_base_interface`.
*/
template<typename NodeT>
class NodeFactoryTemplate : public NodeFactory
{
public:
NodeFactoryTemplate() = default;
virtual ~NodeFactoryTemplate() = default;

/// Create an instance of a component
/**
* \param[in] options Additional options used in the construction of the component.
*/
virtual
wjwwood marked this conversation as resolved.
Show resolved Hide resolved
NodeInstanceWrapper
create_node_instance(const rclcpp::NodeOptions & options)
{
auto node = std::make_shared<NodeT>(options);

return NodeInstanceWrapper(
node, std::bind(&NodeT::get_node_base_interface, node));
}
};
} // namespace rclcpp_components

#endif // RCLCPP_COMPONENTS__NODE_FACTORY_TEMPLATE_HPP__
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright 2019 Open Source Robotics Foundation, Inc.
//
// 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.

#ifndef RCLCPP_COMPONENTS__NODE_INSTANCE_WRAPPER_HPP__
#define RCLCPP_COMPONENTS__NODE_INSTANCE_WRAPPER_HPP__

#include <functional>
#include <memory>

#include "rclcpp/node_interfaces/node_base_interface.hpp"

namespace rclcpp_components
{
/// The NodeInstanceWrapper encapsulates the node instance.
class NodeInstanceWrapper
{
public:
using NodeBaseInterfaceGetter = std::function<
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr(const std::shared_ptr<void> &)>;

NodeInstanceWrapper()
: node_instance_(nullptr)
{}

NodeInstanceWrapper(
std::shared_ptr<void> node_instance,
NodeBaseInterfaceGetter node_base_interface_getter)
: node_instance_(node_instance), node_base_interface_getter_(node_base_interface_getter)
{}

/// Get a type-erased pointer to the original Node instance
/**
* This is only for debugging and special cases.
* For most cases `get_node_base_interface` will be sufficient
wjwwood marked this conversation as resolved.
Show resolved Hide resolved
* \return Shared pointer to the encapsulated Node instance.
*/
const std::shared_ptr<void>
get_node_instance() const
{
return node_instance_;
}

/// Get NodeBaseInterface pointer for the encapsulated Node Instance.
/**
* \return Shared NodeBaseInterface pointer of the encapsulated Node instance.
*/
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
get_node_base_interface()
{
return node_base_interface_getter_(node_instance_);
}

private:
std::shared_ptr<void> node_instance_;
NodeBaseInterfaceGetter node_base_interface_getter_;
};
} // namespace rclcpp_components

#endif // RCLCPP_COMPONENTS__NODE_INSTANCE_WRAPPER_HPP__
Loading