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 rclcpp_generic, a publisher and subscription for serialized messages #1452

Merged
merged 43 commits into from
Apr 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
06e9272
Copying files from rosbag2
nnmm Nov 11, 2020
93fc497
Rebrand into rclcpp_generic
nnmm Nov 11, 2020
83be9dc
Review feedback
nnmm Nov 26, 2020
513c1b8
Move rclpp_generic into rclcpp
nnmm Dec 17, 2020
1481f81
Rename namespace rclcpp_generic to rclcpp::generic
nnmm Jan 5, 2021
4a8bfbc
Free 'create' functions instead of static functions in class
nnmm Jan 7, 2021
8e923ee
Remove 'generic' subdirectory and namespace hierarchy
nnmm Feb 22, 2021
4b82f3a
Order includes according to style guide
nnmm Feb 22, 2021
aa9f827
Remove extra README.md
nnmm Mar 1, 2021
f41f738
Also add brief to class docs
nnmm Mar 1, 2021
ff8c8ef
Make ament_index_cpp a build_depend
nnmm Mar 1, 2021
9a2607e
Add to rclcpp.hpp
nnmm Mar 1, 2021
d02fd9d
Remove memory_management, use rclcpp::SerializedMessage in GenericPub…
nnmm Mar 1, 2021
be8eea8
Clean up the typesupport_helpers
nnmm Mar 1, 2021
b7c8a26
Use make_shared, add UnimplementedError
nnmm Mar 1, 2021
fb39f2e
Add more comments, make member variable private, remove unnecessary i…
nnmm Mar 8, 2021
66cca2a
Apply suggestions from code review
nnmm Mar 8, 2021
e338ceb
Rename test
nnmm Mar 8, 2021
221efa6
Update copyright and remove ament_target_dependencies for test
nnmm Mar 12, 2021
6d816a2
Accept PublisherOptions and SubscriptionOptions
nnmm Mar 12, 2021
ee68c11
Remove target_include_directories
nnmm Mar 15, 2021
78b2fc2
Add explanatory comment to SubscriptionBase
nnmm Mar 17, 2021
1fabb9a
Use kSolibPrefix and kSolibExtension from rcpputils
nnmm Mar 17, 2021
eb3c70e
Fix downstream build failure by making ament_index_cpp a build_export…
nnmm Mar 22, 2021
3a2ee61
Use path_for_library(), fix documentation nitpicks
nnmm Mar 25, 2021
a90c915
Improve error handling in get_typesupport_handle
nnmm Mar 29, 2021
3a6aad4
Accept SubscriptionOptions in GenericSubscription
nnmm Mar 29, 2021
fb5af58
Make use of PublisherOptions in GenericPublisher
nnmm Mar 29, 2021
4f26f36
Document typesupport_helpers
nnmm Mar 29, 2021
9450c3d
Improve documentation
nnmm Mar 29, 2021
2ec829b
Use std::function instead of function pointer
nnmm Mar 29, 2021
7c18bdc
Minimize vertical whitespace
nnmm Mar 29, 2021
9c6f0ed
Add TODO for callback with message info
nnmm Mar 29, 2021
dc4ddbb
Link issue in TODO
nnmm Mar 29, 2021
dc347c9
Add missing include for functional
nnmm Mar 31, 2021
34d7316
Fix compilation
jacobperron Apr 1, 2021
f5d8d14
Fix lint
jacobperron Apr 1, 2021
f585d66
Address review comments (#1)
Karsten1987 Apr 2, 2021
be5453c
Refactor typesupport helpers
jacobperron Apr 2, 2021
66468bf
Remove note about ament from classes
jacobperron Apr 2, 2021
e584230
Fix formatting
jacobperron Apr 2, 2021
3541fe6
Fix warning
jacobperron Apr 2, 2021
5742f7d
Add missing visibility macros
jacobperron Apr 2, 2021
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
12 changes: 9 additions & 3 deletions rclcpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ project(rclcpp)
find_package(Threads REQUIRED)

find_package(ament_cmake_ros REQUIRED)
find_package(ament_index_cpp REQUIRED)
find_package(builtin_interfaces REQUIRED)
find_package(libstatistics_collector REQUIRED)
find_package(rcl REQUIRED)
Expand Down Expand Up @@ -51,12 +52,14 @@ set(${PROJECT_NAME}_SRCS
src/rclcpp/executable_list.cpp
src/rclcpp/executor.cpp
src/rclcpp/executors.cpp
src/rclcpp/expand_topic_or_service_name.cpp
src/rclcpp/executors/multi_threaded_executor.cpp
src/rclcpp/executors/single_threaded_executor.cpp
src/rclcpp/executors/static_executor_entities_collector.cpp
src/rclcpp/executors/static_single_threaded_executor.cpp
src/rclcpp/expand_topic_or_service_name.cpp
src/rclcpp/future_return_code.cpp
src/rclcpp/generic_publisher.cpp
src/rclcpp/generic_subscription.cpp
src/rclcpp/graph_listener.cpp
src/rclcpp/guard_condition.cpp
src/rclcpp/init_options.cpp
Expand All @@ -67,7 +70,6 @@ set(${PROJECT_NAME}_SRCS
src/rclcpp/memory_strategy.cpp
src/rclcpp/message_info.cpp
src/rclcpp/node.cpp
src/rclcpp/node_options.cpp
src/rclcpp/node_interfaces/node_base.cpp
src/rclcpp/node_interfaces/node_clock.cpp
src/rclcpp/node_interfaces/node_graph.cpp
Expand All @@ -78,13 +80,14 @@ set(${PROJECT_NAME}_SRCS
src/rclcpp/node_interfaces/node_timers.cpp
src/rclcpp/node_interfaces/node_topics.cpp
src/rclcpp/node_interfaces/node_waitables.cpp
src/rclcpp/node_options.cpp
src/rclcpp/parameter.cpp
src/rclcpp/parameter_value.cpp
src/rclcpp/parameter_client.cpp
src/rclcpp/parameter_event_handler.cpp
src/rclcpp/parameter_events_filter.cpp
src/rclcpp/parameter_map.cpp
src/rclcpp/parameter_service.cpp
src/rclcpp/parameter_value.cpp
src/rclcpp/publisher_base.cpp
src/rclcpp/qos.cpp
src/rclcpp/qos_event.cpp
Expand All @@ -99,6 +102,7 @@ set(${PROJECT_NAME}_SRCS
src/rclcpp/time_source.cpp
src/rclcpp/timer.cpp
src/rclcpp/type_support.cpp
src/rclcpp/typesupport_helpers.cpp
src/rclcpp/utilities.cpp
src/rclcpp/wait_set_policies/detail/write_preferring_read_write_lock.cpp
src/rclcpp/waitable.cpp
Expand Down Expand Up @@ -179,6 +183,7 @@ target_include_directories(${PROJECT_NAME} PUBLIC
target_link_libraries(${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT})
# specific order: dependents before dependencies
ament_target_dependencies(${PROJECT_NAME}
"ament_index_cpp"
"libstatistics_collector"
"rcl"
"rcl_yaml_param_parser"
Expand Down Expand Up @@ -209,6 +214,7 @@ ament_export_include_directories(include)
ament_export_libraries(${PROJECT_NAME})
ament_export_targets(${PROJECT_NAME})

ament_export_dependencies(ament_index_cpp)
ament_export_dependencies(libstatistics_collector)
ament_export_dependencies(rcl)
ament_export_dependencies(rcpputils)
Expand Down
69 changes: 69 additions & 0 deletions rclcpp/include/rclcpp/create_generic_publisher.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright 2020, Apex.AI 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__CREATE_GENERIC_PUBLISHER_HPP_
#define RCLCPP__CREATE_GENERIC_PUBLISHER_HPP_

#include <memory>
#include <string>
#include <utility>

#include "rclcpp/generic_publisher.hpp"
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
#include "rclcpp/publisher_options.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/typesupport_helpers.hpp"

namespace rclcpp
{

/// Create and return a GenericPublisher.
/**
* The returned pointer will never be empty, but this function can throw various exceptions, for
* instance when the message's package can not be found on the AMENT_PREFIX_PATH.
Copy link
Member

Choose a reason for hiding this comment

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

It would be better, but I won't require it, if the exceptions were detailed individually using the \throws doxygen directive.

*
* \param topics_interface NodeTopicsInterface pointer used in parts of the setup
* \param topic_name Topic name
* \param topic_type Topic type
* \param qos %QoS settings
* \param options %Publisher options.
* Not all publisher options are currently respected, the only relevant options for this
* publisher are `event_callbacks`, `use_default_callbacks`, and `%callback_group`.
*/
template<typename AllocatorT = std::allocator<void>>
std::shared_ptr<GenericPublisher> create_generic_publisher(
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr topics_interface,
const std::string & topic_name,
const std::string & topic_type,
const rclcpp::QoS & qos,
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options = (
rclcpp::PublisherOptionsWithAllocator<AllocatorT>()
)
)
{
auto ts_lib = rclcpp::get_typesupport_library(topic_type, "rosidl_typesupport_cpp");
auto pub = std::make_shared<GenericPublisher>(
topics_interface->get_node_base_interface(),
std::move(ts_lib),
topic_name,
topic_type,
qos,
options);
topics_interface->add_publisher(pub, options.callback_group);
return pub;
}

} // namespace rclcpp

#endif // RCLCPP__CREATE_GENERIC_PUBLISHER_HPP_
79 changes: 79 additions & 0 deletions rclcpp/include/rclcpp/create_generic_subscription.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright 2020, Apex.AI 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__CREATE_GENERIC_SUBSCRIPTION_HPP_
#define RCLCPP__CREATE_GENERIC_SUBSCRIPTION_HPP_

#include <functional>
#include <memory>
#include <string>
#include <utility>

#include "rcl/subscription.h"
#include "rclcpp/generic_subscription.hpp"
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/serialized_message.hpp"
#include "rclcpp/subscription_options.hpp"
#include "rclcpp/typesupport_helpers.hpp"

namespace rclcpp
{

/// Create and return a GenericSubscription.
/**
* The returned pointer will never be empty, but this function can throw various exceptions, for
* instance when the message's package can not be found on the AMENT_PREFIX_PATH.
*
* \param topics_interface NodeTopicsInterface pointer used in parts of the setup.
* \param topic_name Topic name
* \param topic_type Topic type
* \param qos %QoS settings
* \param callback Callback for new messages of serialized form
* \param options %Publisher options.
* Not all publisher options are currently respected, the only relevant options for this
* publisher are `event_callbacks`, `use_default_callbacks`, and `%callback_group`.
*/
template<typename AllocatorT = std::allocator<void>>
std::shared_ptr<GenericSubscription> create_generic_subscription(
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr topics_interface,
const std::string & topic_name,
const std::string & topic_type,
const rclcpp::QoS & qos,
std::function<void(std::shared_ptr<rclcpp::SerializedMessage>)> callback,
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
)
)
{
auto ts_lib = rclcpp::get_typesupport_library(
topic_type, "rosidl_typesupport_cpp");
Comment on lines +60 to +61
Copy link
Member

Choose a reason for hiding this comment

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

I don't know how expensive this operation is, but it might be nice to have an alternate API to let users pass in a the typesupport library object directly (instead of a string). This way they can optionally cache the object for repeated calls to create_generic_subscription and/or create_generic_publisher.

Something to think about; I don't think this comment should block this PR.

Copy link
Member

Choose a reason for hiding this comment

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

I guess users could always construct GenericSubscription (or GenericPublisher) directly if they want to do this.

Copy link
Contributor

Choose a reason for hiding this comment

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

we can always add an overload for this function later on. I don't see any API/ABI breaks here.


auto subscription = std::make_shared<GenericSubscription>(
topics_interface->get_node_base_interface(),
std::move(ts_lib),
topic_name,
topic_type,
qos,
callback,
options);

topics_interface->add_subscription(subscription, options.callback_group);

return subscription;
}

} // namespace rclcpp

#endif // RCLCPP__CREATE_GENERIC_SUBSCRIPTION_HPP_
127 changes: 127 additions & 0 deletions rclcpp/include/rclcpp/generic_publisher.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// Copyright 2018, Bosch Software Innovations GmbH.
// Copyright 2021, Apex.AI 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__GENERIC_PUBLISHER_HPP_
#define RCLCPP__GENERIC_PUBLISHER_HPP_

#include <memory>
#include <string>

#include "rcpputils/shared_library.hpp"

#include "rclcpp/callback_group.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
#include "rclcpp/publisher_base.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/serialized_message.hpp"
#include "rclcpp/typesupport_helpers.hpp"
#include "rclcpp/visibility_control.hpp"

namespace rclcpp
{

/// %Publisher for serialized messages whose type is not known at compile time.
/**
* Since the type is not known at compile time, this is not a template, and the dynamic library
* containing type support information has to be identified and loaded based on the type name.
*
* It does not support intra-process handling.
*/
class GenericPublisher : public rclcpp::PublisherBase
{
public:
// cppcheck-suppress unknownMacro
RCLCPP_SMART_PTR_DEFINITIONS(GenericPublisher)

/// Constructor.
/**
* In order to properly publish to a topic, this publisher needs to be added to
* the node_topic_interface of the node passed into this constructor.
nnmm marked this conversation as resolved.
Show resolved Hide resolved
*
* \sa rclcpp::Node::create_generic_publisher() or rclcpp::create_generic_publisher() for
* creating an instance of this class and adding it to the node_topic_interface.
*
* \param node_base Pointer to parent node's NodeBaseInterface
* \param ts_lib Type support library, needs to correspond to topic_type
* \param topic_name Topic name
* \param topic_type Topic type
* \param qos %QoS settings
* \param callback Callback for new messages of serialized form
* \param options %Publisher options.
* Not all publisher options are currently respected, the only relevant options for this
* publisher are `event_callbacks`, `use_default_callbacks`, and `%callback_group`.
*/
template<typename AllocatorT = std::allocator<void>>
GenericPublisher(
rclcpp::node_interfaces::NodeBaseInterface * node_base,
std::shared_ptr<rcpputils::SharedLibrary> ts_lib,
const std::string & topic_name,
const std::string & topic_type,
const rclcpp::QoS & qos,
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options)
: rclcpp::PublisherBase(
node_base,
topic_name,
*rclcpp::get_typesupport_handle(topic_type, "rosidl_typesupport_cpp", *ts_lib),
options.template to_rcl_publisher_options<rclcpp::SerializedMessage>(qos)),
ts_lib_(ts_lib)
{
// This is unfortunately duplicated with the code in publisher.hpp.
// TODO(nnmm): Deduplicate by moving this into PublisherBase.
if (options.event_callbacks.deadline_callback) {
this->add_event_handler(
options.event_callbacks.deadline_callback,
RCL_PUBLISHER_OFFERED_DEADLINE_MISSED);
}
if (options.event_callbacks.liveliness_callback) {
this->add_event_handler(
options.event_callbacks.liveliness_callback,
RCL_PUBLISHER_LIVELINESS_LOST);
}
if (options.event_callbacks.incompatible_qos_callback) {
this->add_event_handler(
options.event_callbacks.incompatible_qos_callback,
RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS);
} else if (options.use_default_callbacks) {
// Register default callback when not specified
try {
this->add_event_handler(
[this](QOSOfferedIncompatibleQoSInfo & info) {
this->default_incompatible_qos_callback(info);
},
RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS);
} catch (UnsupportedEventTypeException & /*exc*/) {
// pass
}
}
}

RCLCPP_PUBLIC
Karsten1987 marked this conversation as resolved.
Show resolved Hide resolved
virtual ~GenericPublisher() = default;

/// Publish a rclcpp::SerializedMessage.
RCLCPP_PUBLIC
void publish(const rclcpp::SerializedMessage & message);

private:
// The type support library should stay loaded, so it is stored in the GenericPublisher
std::shared_ptr<rcpputils::SharedLibrary> ts_lib_;
};

} // namespace rclcpp

#endif // RCLCPP__GENERIC_PUBLISHER_HPP_
Loading