From c496ccce075660585c5fab5c85d95d12dd38de9d Mon Sep 17 00:00:00 2001 From: Benjamin-Tan Date: Sat, 6 Apr 2024 19:59:30 +0800 Subject: [PATCH 01/14] Use SharedPtr and update base class in preparation for lifecycle node --- image_transport/CMakeLists.txt | 2 + .../image_transport/camera_publisher.hpp | 2 +- .../image_transport/camera_subscriber.hpp | 2 +- .../image_transport/image_transport.hpp | 8 +-- .../include/image_transport/publisher.hpp | 2 +- .../image_transport/publisher_plugin.hpp | 57 ++++++++++++++++++- .../simple_publisher_plugin.hpp | 24 +++++--- .../simple_subscriber_plugin.hpp | 26 ++++++--- .../include/image_transport/subscriber.hpp | 2 +- .../image_transport/subscriber_filter.hpp | 4 +- .../image_transport/subscriber_plugin.hpp | 43 ++++++++++++-- image_transport/src/camera_publisher.cpp | 4 +- image_transport/src/camera_subscriber.cpp | 4 +- image_transport/src/image_transport.cpp | 20 +++---- image_transport/src/publisher.cpp | 4 +- image_transport/src/republish.cpp | 8 +-- image_transport/src/subscriber.cpp | 4 +- image_transport/test/test_message_passing.cpp | 8 +-- image_transport/test/test_publisher.cpp | 4 +- image_transport/test/test_qos_override.cpp | 16 +++--- image_transport/test/test_remapping.cpp | 4 +- image_transport/test/test_subscriber.cpp | 6 +- 22 files changed, 179 insertions(+), 75 deletions(-) diff --git a/image_transport/CMakeLists.txt b/image_transport/CMakeLists.txt index 089d5a12..55c1a4b0 100644 --- a/image_transport/CMakeLists.txt +++ b/image_transport/CMakeLists.txt @@ -17,6 +17,7 @@ find_package(ament_cmake_ros REQUIRED) find_package(message_filters REQUIRED) find_package(pluginlib REQUIRED) find_package(rclcpp REQUIRED) +find_package(rclcpp_lifecycle REQUIRED) find_package(rclcpp_components REQUIRED) find_package(sensor_msgs REQUIRED) @@ -37,6 +38,7 @@ target_include_directories(${PROJECT_NAME} PUBLIC target_link_libraries(${PROJECT_NAME} PUBLIC message_filters::message_filters rclcpp::rclcpp + rclcpp_lifecycle::rclcpp_lifecycle ${sensor_msgs_TARGETS}) target_link_libraries(${PROJECT_NAME} PRIVATE pluginlib::pluginlib) diff --git a/image_transport/include/image_transport/camera_publisher.hpp b/image_transport/include/image_transport/camera_publisher.hpp index 9ed81b07..4269b738 100644 --- a/image_transport/include/image_transport/camera_publisher.hpp +++ b/image_transport/include/image_transport/camera_publisher.hpp @@ -69,7 +69,7 @@ class CameraPublisher IMAGE_TRANSPORT_PUBLIC CameraPublisher( - rclcpp::Node * node, + rclcpp::Node::SharedPtr node, const std::string & base_topic, rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::PublisherOptions = rclcpp::PublisherOptions()); diff --git a/image_transport/include/image_transport/camera_subscriber.hpp b/image_transport/include/image_transport/camera_subscriber.hpp index 5157111d..4ab8f1ce 100644 --- a/image_transport/include/image_transport/camera_subscriber.hpp +++ b/image_transport/include/image_transport/camera_subscriber.hpp @@ -71,7 +71,7 @@ class CameraSubscriber IMAGE_TRANSPORT_PUBLIC CameraSubscriber( - rclcpp::Node * node, + rclcpp::Node::SharedPtr node, const std::string & base_topic, const Callback & callback, const std::string & transport, diff --git a/image_transport/include/image_transport/image_transport.hpp b/image_transport/include/image_transport/image_transport.hpp index e430cd92..2a39dd9c 100644 --- a/image_transport/include/image_transport/image_transport.hpp +++ b/image_transport/include/image_transport/image_transport.hpp @@ -51,7 +51,7 @@ namespace image_transport */ IMAGE_TRANSPORT_PUBLIC Publisher create_publisher( - rclcpp::Node * node, + rclcpp::Node::SharedPtr node, const std::string & base_topic, rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::PublisherOptions options = rclcpp::PublisherOptions()); @@ -61,7 +61,7 @@ Publisher create_publisher( */ IMAGE_TRANSPORT_PUBLIC Subscriber create_subscription( - rclcpp::Node * node, + rclcpp::Node::SharedPtr node, const std::string & base_topic, const Subscriber::Callback & callback, const std::string & transport, @@ -73,7 +73,7 @@ Subscriber create_subscription( */ IMAGE_TRANSPORT_PUBLIC CameraPublisher create_camera_publisher( - rclcpp::Node * node, + rclcpp::Node::SharedPtr node, const std::string & base_topic, rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::PublisherOptions pub_options = rclcpp::PublisherOptions()); @@ -83,7 +83,7 @@ CameraPublisher create_camera_publisher( */ IMAGE_TRANSPORT_PUBLIC CameraSubscriber create_camera_subscription( - rclcpp::Node * node, + rclcpp::Node::SharedPtr node, const std::string & base_topic, const CameraSubscriber::Callback & callback, const std::string & transport, diff --git a/image_transport/include/image_transport/publisher.hpp b/image_transport/include/image_transport/publisher.hpp index dc28d017..9e8ca067 100644 --- a/image_transport/include/image_transport/publisher.hpp +++ b/image_transport/include/image_transport/publisher.hpp @@ -70,7 +70,7 @@ class Publisher IMAGE_TRANSPORT_PUBLIC Publisher( - rclcpp::Node * nh, + rclcpp::Node::SharedPtr nh, const std::string & base_topic, PubLoaderPtr loader, rmw_qos_profile_t custom_qos, diff --git a/image_transport/include/image_transport/publisher_plugin.hpp b/image_transport/include/image_transport/publisher_plugin.hpp index d899349e..8820f754 100644 --- a/image_transport/include/image_transport/publisher_plugin.hpp +++ b/image_transport/include/image_transport/publisher_plugin.hpp @@ -33,6 +33,7 @@ #include #include "rclcpp/node.hpp" +#include "rclcpp_lifecycle/lifecycle_node.hpp" #include "sensor_msgs/msg/image.hpp" #include "image_transport/single_subscriber_publisher.hpp" @@ -63,14 +64,56 @@ class PublisherPlugin * \brief Advertise a topic, simple version. */ void advertise( - rclcpp::Node * nh, + rclcpp::Node::SharedPtr nh, const std::string & base_topic, rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::PublisherOptions options = rclcpp::PublisherOptions()) { - advertiseImpl(nh, base_topic, custom_qos, options); + if (impl_) { + throw std::runtime_error("advertise has been called previously!"); + } + impl_ = std::make_unique(); + impl_->node_ = nh; + advertise(base_topic, custom_qos, options); } + void advertise( + rclcpp_lifecycle::LifecycleNode::SharedPtr nh, + const std::string & base_topic, + rmw_qos_profile_t custom_qos = rmw_qos_profile_default, + rclcpp::PublisherOptions options = rclcpp::PublisherOptions()) + { + if (impl_) { + throw std::runtime_error("advertise has been called previously!"); + } + impl_ = std::make_unique(); + impl_->lifecycle_node_ = nh; + advertise(base_topic, custom_qos, options); + } + + void advertise( + const std::string & base_topic, + rmw_qos_profile_t custom_qos = rmw_qos_profile_default, + rclcpp::PublisherOptions options = rclcpp::PublisherOptions()) + { + advertiseImpl(base_topic, custom_qos, options); + } + + bool get_node(rclcpp::Node::SharedPtr node) const { + if (impl_ && impl_->node_) { + node = impl_->node_; + return true; + } + return false; + } + + bool get_node(rclcpp_lifecycle::LifecycleNode::SharedPtr node) const { + if (impl_ && impl_->lifecycle_node_) { + node = impl_->lifecycle_node_; + return true; + } + return false; + } /** * \brief Returns the number of subscribers that are currently connected to * this PublisherPlugin. @@ -135,10 +178,18 @@ class PublisherPlugin * \brief Advertise a topic. Must be implemented by the subclass. */ virtual void advertiseImpl( - rclcpp::Node * node, const std::string & base_topic, rmw_qos_profile_t custom_qos, rclcpp::PublisherOptions options) = 0; + +private: + struct Impl + { + rclcpp::Node::SharedPtr node_; + rclcpp_lifecycle::LifecycleNode::SharedPtr lifecycle_node_; + }; + + std::unique_ptr impl_; }; } // namespace image_transport diff --git a/image_transport/include/image_transport/simple_publisher_plugin.hpp b/image_transport/include/image_transport/simple_publisher_plugin.hpp index f088c874..748d6ebe 100644 --- a/image_transport/include/image_transport/simple_publisher_plugin.hpp +++ b/image_transport/include/image_transport/simple_publisher_plugin.hpp @@ -99,17 +99,25 @@ class SimplePublisherPlugin : public PublisherPlugin protected: void advertiseImpl( - rclcpp::Node * node, const std::string & base_topic, rmw_qos_profile_t custom_qos, rclcpp::PublisherOptions options) override { std::string transport_topic = getTopicToAdvertise(base_topic); - simple_impl_ = std::make_unique(node); + auto qos = rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(custom_qos), custom_qos); + + simple_impl_ = std::make_unique(); + if (get_node(simple_impl_->node_)) { + simple_impl_->logger_ = simple_impl_->node_->get_logger(); + simple_impl_->pub_ = simple_impl_->node_->template create_publisher(transport_topic, qos, options); + } else if (get_node(simple_impl_->lifecycle_node_)) { + simple_impl_->logger_ = simple_impl_->lifecycle_node_->get_logger(); + simple_impl_->pub_ = simple_impl_->lifecycle_node_->template create_publisher(transport_topic, qos, options); + } else { + throw std::runtime_error("Not a standard node or lifecycle node!"); + } RCLCPP_DEBUG(simple_impl_->logger_, "getTopicToAdvertise: %s", transport_topic.c_str()); - auto qos = rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(custom_qos), custom_qos); - simple_impl_->pub_ = node->create_publisher(transport_topic, qos, options); } //! Generic function for publishing the internal message type. @@ -140,13 +148,13 @@ class SimplePublisherPlugin : public PublisherPlugin private: struct SimplePublisherPluginImpl { - explicit SimplePublisherPluginImpl(rclcpp::Node * node) - : node_(node), - logger_(node->get_logger()) + explicit SimplePublisherPluginImpl() + : logger_(rclcpp::get_logger("simple_publisher_plugin_impl")) { } - rclcpp::Node * node_; + rclcpp::Node::SharedPtr node_; + rclcpp_lifecycle::LifecycleNode::SharedPtr lifecycle_node_; rclcpp::Logger logger_; typename rclcpp::Publisher::SharedPtr pub_; }; diff --git a/image_transport/include/image_transport/simple_subscriber_plugin.hpp b/image_transport/include/image_transport/simple_subscriber_plugin.hpp index 189e07ab..d27ace78 100644 --- a/image_transport/include/image_transport/simple_subscriber_plugin.hpp +++ b/image_transport/include/image_transport/simple_subscriber_plugin.hpp @@ -109,7 +109,6 @@ class SimpleSubscriberPlugin : public SubscriberPlugin } void subscribeImpl( - rclcpp::Node * node, const std::string & base_topic, const Callback & callback, rmw_qos_profile_t custom_qos, @@ -120,17 +119,30 @@ class SimpleSubscriberPlugin : public SubscriberPlugin // ros::NodeHandle param_nh(transport_hints.getParameterNH(), getTransportName()); // auto qos = rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(custom_qos), custom_qos); - impl_->sub_ = node->create_subscription( - getTopicToSubscribe(base_topic), qos, - [this, callback](const typename std::shared_ptr msg) { - internalCallback(msg, callback); - }, - options); + if (get_node(impl_->node_)) { + impl_->sub_ = impl_->node_->template create_subscription( + getTopicToSubscribe(base_topic), qos, + [this, callback](const typename std::shared_ptr msg) { + internalCallback(msg, callback); + }, + options); + } else if (get_node(impl_->lifecycle_node_)) { + impl_->sub_ = impl_->lifecycle_node_->template create_subscription( + getTopicToSubscribe(base_topic), qos, + [this, callback](const typename std::shared_ptr msg) { + internalCallback(msg, callback); + }, + options); + } else { + throw std::runtime_error("Not a standard node or lifecycle node!"); + } } private: struct Impl { + rclcpp::Node::SharedPtr node_; + rclcpp_lifecycle::LifecycleNode::SharedPtr lifecycle_node_; rclcpp::SubscriptionBase::SharedPtr sub_; }; diff --git a/image_transport/include/image_transport/subscriber.hpp b/image_transport/include/image_transport/subscriber.hpp index f0b87245..af45e1bf 100644 --- a/image_transport/include/image_transport/subscriber.hpp +++ b/image_transport/include/image_transport/subscriber.hpp @@ -68,7 +68,7 @@ class Subscriber IMAGE_TRANSPORT_PUBLIC Subscriber( - rclcpp::Node * node, + rclcpp::Node::SharedPtr node, const std::string & base_topic, const Callback & callback, SubLoaderPtr loader, diff --git a/image_transport/include/image_transport/subscriber_filter.hpp b/image_transport/include/image_transport/subscriber_filter.hpp index 37b216ed..2a588dfc 100644 --- a/image_transport/include/image_transport/subscriber_filter.hpp +++ b/image_transport/include/image_transport/subscriber_filter.hpp @@ -77,7 +77,7 @@ class SubscriberFilter : public message_filters::SimpleFilter(); + impl_->node_ = node; + + return subscribeImpl(base_topic, callback, custom_qos, options); } /** * \brief Subscribe to an image topic, version for bare function. */ void subscribe( - rclcpp::Node * node, const std::string & base_topic, + rclcpp::Node::SharedPtr node, const std::string & base_topic, void (* fp)(const sensor_msgs::msg::Image::ConstSharedPtr &), rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::SubscriptionOptions options = rclcpp::SubscriptionOptions()) @@ -93,7 +100,7 @@ class IMAGE_TRANSPORT_PUBLIC SubscriberPlugin */ template void subscribe( - rclcpp::Node * node, const std::string & base_topic, + rclcpp::Node::SharedPtr node, const std::string & base_topic, void (T::* fp)(const sensor_msgs::msg::Image::ConstSharedPtr &), T * obj, rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::SubscriptionOptions options = rclcpp::SubscriptionOptions()) @@ -108,7 +115,7 @@ class IMAGE_TRANSPORT_PUBLIC SubscriberPlugin */ template void subscribe( - rclcpp::Node * node, const std::string & base_topic, + rclcpp::Node::SharedPtr node, const std::string & base_topic, void (T::* fp)(const sensor_msgs::msg::Image::ConstSharedPtr &), std::shared_ptr & obj, rmw_qos_profile_t custom_qos = rmw_qos_profile_default) @@ -118,6 +125,22 @@ class IMAGE_TRANSPORT_PUBLIC SubscriberPlugin std::bind(fp, obj, std::placeholders::_1), custom_qos); } + bool get_node(rclcpp::Node::SharedPtr node) const { + if (impl_ && impl_->node_) { + node = impl_->node_; + return true; + } + return false; + } + + bool get_node(rclcpp_lifecycle::LifecycleNode::SharedPtr node) const { + if (impl_ && impl_->lifecycle_node_) { + node = impl_->lifecycle_node_; + return true; + } + return false; + } + /** * \brief Get the transport-specific communication topic. */ @@ -147,11 +170,19 @@ class IMAGE_TRANSPORT_PUBLIC SubscriberPlugin * \brief Subscribe to an image transport topic. Must be implemented by the subclass. */ virtual void subscribeImpl( - rclcpp::Node * node, const std::string & base_topic, const Callback & callback, rmw_qos_profile_t custom_qos, rclcpp::SubscriptionOptions options) = 0; + +private: + struct Impl + { + rclcpp::Node::SharedPtr node_; + rclcpp_lifecycle::LifecycleNode::SharedPtr lifecycle_node_; + }; + + std::unique_ptr impl_; }; } // namespace image_transport diff --git a/image_transport/src/camera_publisher.cpp b/image_transport/src/camera_publisher.cpp index 7c1ae450..f51fcb45 100644 --- a/image_transport/src/camera_publisher.cpp +++ b/image_transport/src/camera_publisher.cpp @@ -43,7 +43,7 @@ namespace image_transport struct CameraPublisher::Impl { - explicit Impl(rclcpp::Node * node) + explicit Impl(rclcpp::Node::SharedPtr node) : logger_(node->get_logger()), unadvertised_(false) { @@ -75,7 +75,7 @@ struct CameraPublisher::Impl }; CameraPublisher::CameraPublisher( - rclcpp::Node * node, + rclcpp::Node::SharedPtr node, const std::string & base_topic, rmw_qos_profile_t custom_qos, rclcpp::PublisherOptions pub_options) diff --git a/image_transport/src/camera_subscriber.cpp b/image_transport/src/camera_subscriber.cpp index 3075564a..99d5dce9 100644 --- a/image_transport/src/camera_subscriber.cpp +++ b/image_transport/src/camera_subscriber.cpp @@ -51,7 +51,7 @@ struct CameraSubscriber::Impl using CameraInfo = sensor_msgs::msg::CameraInfo; using TimeSync = message_filters::TimeSynchronizer; - explicit Impl(rclcpp::Node * node) + explicit Impl(rclcpp::Node::SharedPtr node) : logger_(node->get_logger()), sync_(10), unsubscribed_(false), @@ -107,7 +107,7 @@ struct CameraSubscriber::Impl }; CameraSubscriber::CameraSubscriber( - rclcpp::Node * node, + rclcpp::Node::SharedPtr node, const std::string & base_topic, const Callback & callback, const std::string & transport, diff --git a/image_transport/src/image_transport.cpp b/image_transport/src/image_transport.cpp index dfddcb91..5b1545b3 100644 --- a/image_transport/src/image_transport.cpp +++ b/image_transport/src/image_transport.cpp @@ -57,7 +57,7 @@ struct Impl static Impl * kImpl = new Impl(); Publisher create_publisher( - rclcpp::Node * node, + rclcpp::Node::SharedPtr node, const std::string & base_topic, rmw_qos_profile_t custom_qos, rclcpp::PublisherOptions options) @@ -66,7 +66,7 @@ Publisher create_publisher( } Subscriber create_subscription( - rclcpp::Node * node, + rclcpp::Node::SharedPtr node, const std::string & base_topic, const Subscriber::Callback & callback, const std::string & transport, @@ -77,7 +77,7 @@ Subscriber create_subscription( } CameraPublisher create_camera_publisher( - rclcpp::Node * node, + rclcpp::Node::SharedPtr node, const std::string & base_topic, rmw_qos_profile_t custom_qos, rclcpp::PublisherOptions pub_options) @@ -86,7 +86,7 @@ CameraPublisher create_camera_publisher( } CameraSubscriber create_camera_subscription( - rclcpp::Node * node, + rclcpp::Node::SharedPtr node, const std::string & base_topic, const CameraSubscriber::Callback & callback, const std::string & transport, @@ -147,7 +147,7 @@ Publisher ImageTransport::advertise(const std::string & base_topic, uint32_t que (void) latch; rmw_qos_profile_t custom_qos = rmw_qos_profile_default; custom_qos.depth = queue_size; - return create_publisher(impl_->node_.get(), base_topic, custom_qos); + return create_publisher(impl_->node_, base_topic, custom_qos); } Publisher ImageTransport::advertise( @@ -156,7 +156,7 @@ Publisher ImageTransport::advertise( { // TODO(ros2) implement when resolved: https://github.com/ros2/ros2/issues/464 (void) latch; - return create_publisher(impl_->node_.get(), base_topic, custom_qos); + return create_publisher(impl_->node_, base_topic, custom_qos); } Subscriber ImageTransport::subscribe( @@ -168,7 +168,7 @@ Subscriber ImageTransport::subscribe( { (void) tracked_object; return create_subscription( - impl_->node_.get(), base_topic, callback, + impl_->node_, base_topic, callback, getTransportOrDefault(transport_hints), custom_qos, options); } @@ -184,7 +184,7 @@ Subscriber ImageTransport::subscribe( rmw_qos_profile_t custom_qos = rmw_qos_profile_default; custom_qos.depth = queue_size; return create_subscription( - impl_->node_.get(), base_topic, callback, + impl_->node_, base_topic, callback, getTransportOrDefault(transport_hints), custom_qos, options); } @@ -197,7 +197,7 @@ CameraPublisher ImageTransport::advertiseCamera( (void) latch; rmw_qos_profile_t custom_qos = rmw_qos_profile_default; custom_qos.depth = queue_size; - return create_camera_publisher(impl_->node_.get(), base_topic, custom_qos); + return create_camera_publisher(impl_->node_, base_topic, custom_qos); } CameraSubscriber ImageTransport::subscribeCamera( @@ -210,7 +210,7 @@ CameraSubscriber ImageTransport::subscribeCamera( rmw_qos_profile_t custom_qos = rmw_qos_profile_default; custom_qos.depth = queue_size; return create_camera_subscription( - impl_->node_.get(), base_topic, callback, + impl_->node_, base_topic, callback, getTransportOrDefault(transport_hints), custom_qos); } diff --git a/image_transport/src/publisher.cpp b/image_transport/src/publisher.cpp index 0bed7b09..13048c5e 100644 --- a/image_transport/src/publisher.cpp +++ b/image_transport/src/publisher.cpp @@ -48,7 +48,7 @@ namespace image_transport struct Publisher::Impl { - explicit Impl(rclcpp::Node * node) + explicit Impl(rclcpp::Node::SharedPtr node) : logger_(node->get_logger()), unadvertised_(false) { @@ -97,7 +97,7 @@ struct Publisher::Impl }; Publisher::Publisher( - rclcpp::Node * node, const std::string & base_topic, + rclcpp::Node::SharedPtr node, const std::string & base_topic, PubLoaderPtr loader, rmw_qos_profile_t custom_qos, rclcpp::PublisherOptions options) : impl_(std::make_shared(node)) diff --git a/image_transport/src/republish.cpp b/image_transport/src/republish.cpp index 499b7cf6..cfe5e773 100644 --- a/image_transport/src/republish.cpp +++ b/image_transport/src/republish.cpp @@ -109,7 +109,7 @@ void Republisher::initialize() pub_options.qos_overriding_options = qos_override_options; this->pub = image_transport::create_publisher( - this, out_topic, + shared_from_this(), out_topic, rmw_qos_profile_default, pub_options); // Use Publisher::publish as the subscriber callback @@ -121,7 +121,7 @@ void Republisher::initialize() sub_options.qos_overriding_options = qos_override_options; this->sub = image_transport::create_subscription( - this, in_topic, std::bind(pub_mem_fn, &pub, std::placeholders::_1), + shared_from_this(), in_topic, std::bind(pub_mem_fn, &pub, std::placeholders::_1), in_transport, rmw_qos_profile_default, sub_options); } else { // Use one specific transport for output @@ -133,13 +133,13 @@ void Republisher::initialize() std::string lookup_name = Plugin::getLookupName(out_transport); instance = loader->createUniqueInstance(lookup_name); - instance->advertise(this, out_topic); + instance->advertise(shared_from_this(), out_topic); // Use PublisherPlugin::publish as the subscriber callback typedef void (Plugin::* PublishMemFn)(const sensor_msgs::msg::Image::ConstSharedPtr &) const; PublishMemFn pub_mem_fn = &Plugin::publishPtr; this->sub = image_transport::create_subscription( - this, in_topic, + shared_from_this(), in_topic, std::bind(pub_mem_fn, instance.get(), std::placeholders::_1), in_transport); } } diff --git a/image_transport/src/subscriber.cpp b/image_transport/src/subscriber.cpp index 85c7927c..26445f86 100644 --- a/image_transport/src/subscriber.cpp +++ b/image_transport/src/subscriber.cpp @@ -46,7 +46,7 @@ namespace image_transport struct Subscriber::Impl { - Impl(rclcpp::Node * node, SubLoaderPtr loader) + Impl(rclcpp::Node::SharedPtr node, SubLoaderPtr loader) : logger_(node->get_logger()), loader_(loader), unsubscribed_(false) @@ -82,7 +82,7 @@ struct Subscriber::Impl }; Subscriber::Subscriber( - rclcpp::Node * node, + rclcpp::Node::SharedPtr node, const std::string & base_topic, const Callback & callback, SubLoaderPtr loader, diff --git a/image_transport/test/test_message_passing.cpp b/image_transport/test/test_message_passing.cpp index 0a4372c3..87dbd4b3 100644 --- a/image_transport/test/test_message_passing.cpp +++ b/image_transport/test/test_message_passing.cpp @@ -77,9 +77,9 @@ TEST_F(MessagePassingTesting, one_message_passing) rclcpp::executors::SingleThreadedExecutor executor; - auto pub = image_transport::create_publisher(node_.get(), "camera/image"); + auto pub = image_transport::create_publisher(node_, "camera/image"); auto sub = - image_transport::create_subscription(node_.get(), "camera/image", imageCallback, "raw"); + image_transport::create_subscription(node_, "camera/image", imageCallback, "raw"); test_rclcpp::wait_for_subscriber(node_, sub.getTopic()); @@ -114,9 +114,9 @@ TEST_F(MessagePassingTesting, one_camera_message_passing) rclcpp::executors::SingleThreadedExecutor executor; - auto pub = image_transport::create_camera_publisher(node_.get(), "camera/image"); + auto pub = image_transport::create_camera_publisher(node_, "camera/image"); auto sub = image_transport::create_camera_subscription( - node_.get(), "camera/image", + node_, "camera/image", [](const sensor_msgs::msg::Image::ConstSharedPtr & image, const sensor_msgs::msg::CameraInfo::ConstSharedPtr & info) { (void) image; diff --git a/image_transport/test/test_publisher.cpp b/image_transport/test/test_publisher.cpp index 7216b79a..6cd12454 100644 --- a/image_transport/test/test_publisher.cpp +++ b/image_transport/test/test_publisher.cpp @@ -47,7 +47,7 @@ class TestPublisher : public ::testing::Test }; TEST_F(TestPublisher, publisher) { - auto pub = image_transport::create_publisher(node_.get(), "camera/image"); + auto pub = image_transport::create_publisher(node_, "camera/image"); EXPECT_EQ(node_->get_node_graph_interface()->count_publishers("camera/image"), 1u); pub.shutdown(); EXPECT_EQ(node_->get_node_graph_interface()->count_publishers("camera/image"), 0u); @@ -62,7 +62,7 @@ TEST_F(TestPublisher, image_transport_publisher) { } TEST_F(TestPublisher, camera_publisher) { - auto camera_pub = image_transport::create_camera_publisher(node_.get(), "camera/image"); + auto camera_pub = image_transport::create_camera_publisher(node_, "camera/image"); EXPECT_EQ(node_->get_node_graph_interface()->count_publishers("camera/image"), 1u); EXPECT_EQ(node_->get_node_graph_interface()->count_publishers("camera/camera_info"), 1u); camera_pub.shutdown(); diff --git a/image_transport/test/test_qos_override.cpp b/image_transport/test/test_qos_override.cpp index 3b2b7ea3..4f26e6fe 100644 --- a/image_transport/test/test_qos_override.cpp +++ b/image_transport/test/test_qos_override.cpp @@ -64,13 +64,13 @@ class TestQosOverride : public ::testing::Test TEST_F(TestQosOverride, qos_override_publisher_without_options) { auto pub = - image_transport::create_publisher(pub_node_.get(), "camera/image", rmw_qos_profile_default); + image_transport::create_publisher(pub_node_, "camera/image", rmw_qos_profile_default); auto endpoint_info_vec = pub_node_->get_publishers_info_by_topic("camera/image"); EXPECT_EQ(endpoint_info_vec[0].qos_profile().reliability(), rclcpp::ReliabilityPolicy::Reliable); pub.shutdown(); pub = image_transport::create_publisher( - qos_override_pub_node_.get(), "camera/image", rmw_qos_profile_default); + qos_override_pub_node_, "camera/image", rmw_qos_profile_default); endpoint_info_vec = qos_override_pub_node_->get_publishers_info_by_topic("camera/image"); EXPECT_EQ( @@ -90,13 +90,13 @@ TEST_F(TestQosOverride, qos_override_publisher_with_options) { }); auto pub = image_transport::create_publisher( - pub_node_.get(), "camera/image", rmw_qos_profile_default, options); + pub_node_, "camera/image", rmw_qos_profile_default, options); auto endpoint_info_vec = pub_node_->get_publishers_info_by_topic("camera/image"); EXPECT_EQ(endpoint_info_vec[0].qos_profile().reliability(), rclcpp::ReliabilityPolicy::Reliable); pub.shutdown(); pub = image_transport::create_publisher( - qos_override_pub_node_.get(), "camera/image", rmw_qos_profile_default, options); + qos_override_pub_node_, "camera/image", rmw_qos_profile_default, options); endpoint_info_vec = qos_override_pub_node_->get_publishers_info_by_topic("camera/image"); EXPECT_EQ( @@ -110,13 +110,13 @@ TEST_F(TestQosOverride, qos_override_subscriber_without_options) { [](const auto & msg) {(void)msg;}; auto sub = image_transport::create_subscription( - sub_node_.get(), "camera/image", fcn, "raw", rmw_qos_profile_default); + sub_node_, "camera/image", fcn, "raw", rmw_qos_profile_default); auto endpoint_info_vec = sub_node_->get_subscriptions_info_by_topic("camera/image"); EXPECT_EQ(endpoint_info_vec[0].qos_profile().reliability(), rclcpp::ReliabilityPolicy::Reliable); sub.shutdown(); sub = image_transport::create_subscription( - qos_override_sub_node_.get(), "camera/image", fcn, "raw", rmw_qos_profile_default); + qos_override_sub_node_, "camera/image", fcn, "raw", rmw_qos_profile_default); endpoint_info_vec = qos_override_sub_node_->get_subscriptions_info_by_topic("camera/image"); EXPECT_EQ( @@ -138,13 +138,13 @@ TEST_F(TestQosOverride, qos_override_subscriber_with_options) { }); auto sub = image_transport::create_subscription( - sub_node_.get(), "camera/image", fcn, "raw", rmw_qos_profile_default, options); + sub_node_, "camera/image", fcn, "raw", rmw_qos_profile_default, options); auto endpoint_info_vec = sub_node_->get_subscriptions_info_by_topic("camera/image"); EXPECT_EQ(endpoint_info_vec[0].qos_profile().reliability(), rclcpp::ReliabilityPolicy::Reliable); sub.shutdown(); sub = image_transport::create_subscription( - qos_override_sub_node_.get(), "camera/image", fcn, "raw", rmw_qos_profile_default, options); + qos_override_sub_node_, "camera/image", fcn, "raw", rmw_qos_profile_default, options); endpoint_info_vec = qos_override_sub_node_->get_subscriptions_info_by_topic("camera/image"); EXPECT_EQ( diff --git a/image_transport/test/test_remapping.cpp b/image_transport/test/test_remapping.cpp index 9106a710..7194e1ae 100644 --- a/image_transport/test/test_remapping.cpp +++ b/image_transport/test/test_remapping.cpp @@ -73,14 +73,14 @@ TEST_F(TestPublisher, RemappedPublisher) { // Subscribe bool received{false}; auto sub = image_transport::create_subscription( - node_remap_.get(), "old_topic", + node_remap_, "old_topic", [&received](const sensor_msgs::msg::Image::ConstSharedPtr & msg) { (void)msg; received = true; }, "raw"); // Publish - auto pub = image_transport::create_publisher(node_.get(), "new_topic"); + auto pub = image_transport::create_publisher(node_, "new_topic"); ASSERT_EQ("/namespace/new_topic", sub.getTopic()); ASSERT_EQ("/namespace/new_topic", pub.getTopic()); diff --git a/image_transport/test/test_subscriber.cpp b/image_transport/test/test_subscriber.cpp index 75ecc827..1e68529f 100644 --- a/image_transport/test/test_subscriber.cpp +++ b/image_transport/test/test_subscriber.cpp @@ -50,7 +50,7 @@ TEST_F(TestSubscriber, construction_and_destruction) { std::function fcn = [](const auto & msg) {(void)msg;}; - auto sub = image_transport::create_subscription(node_.get(), "camera/image", fcn, "raw"); + auto sub = image_transport::create_subscription(node_, "camera/image", fcn, "raw"); rclcpp::executors::SingleThreadedExecutor executor; executor.spin_node_some(node_); @@ -60,7 +60,7 @@ TEST_F(TestSubscriber, shutdown) { std::function fcn = [](const auto & msg) {(void)msg;}; - auto sub = image_transport::create_subscription(node_.get(), "camera/image", fcn, "raw"); + auto sub = image_transport::create_subscription(node_, "camera/image", fcn, "raw"); EXPECT_EQ(node_->get_node_graph_interface()->count_subscribers("camera/image"), 1u); sub.shutdown(); EXPECT_EQ(node_->get_node_graph_interface()->count_subscribers("camera/image"), 0u); @@ -72,7 +72,7 @@ TEST_F(TestSubscriber, camera_sub_shutdown) { const sensor_msgs::msg::CameraInfo::ConstSharedPtr &)> fcn = [](const auto & msg, const auto &) {(void)msg;}; - auto sub = image_transport::create_camera_subscription(node_.get(), "camera/image", fcn, "raw"); + auto sub = image_transport::create_camera_subscription(node_, "camera/image", fcn, "raw"); EXPECT_EQ(node_->get_node_graph_interface()->count_subscribers("camera/image"), 1u); EXPECT_EQ(node_->get_node_graph_interface()->count_subscribers("camera/camera_info"), 1u); sub.shutdown(); From b0dfb86ac939015a80b7f6eec7495f8c7d3acb7b Mon Sep 17 00:00:00 2001 From: Benjamin-Tan Date: Sat, 6 Apr 2024 20:45:36 +0800 Subject: [PATCH 02/14] Extend lifecycle node to publisher, subscriber --- .../include/image_transport/publisher.hpp | 14 ++++ .../include/image_transport/subscriber.hpp | 18 +++++ .../image_transport/subscriber_plugin.hpp | 67 +++++++++++++++- image_transport/src/publisher.cpp | 80 ++++++++++++++++--- image_transport/src/subscriber.cpp | 50 +++++++++++- 5 files changed, 208 insertions(+), 21 deletions(-) diff --git a/image_transport/include/image_transport/publisher.hpp b/image_transport/include/image_transport/publisher.hpp index 9e8ca067..c7b89343 100644 --- a/image_transport/include/image_transport/publisher.hpp +++ b/image_transport/include/image_transport/publisher.hpp @@ -34,6 +34,7 @@ #include "rclcpp/macros.hpp" #include "rclcpp/node.hpp" +#include "rclcpp_lifecycle/lifecycle_node.hpp" #include "sensor_msgs/msg/image.hpp" @@ -76,6 +77,13 @@ class Publisher rmw_qos_profile_t custom_qos, rclcpp::PublisherOptions options = rclcpp::PublisherOptions()); + IMAGE_TRANSPORT_PUBLIC + Publisher( + rclcpp_lifecycle::LifecycleNode::SharedPtr nh, + const std::string & base_topic, + PubLoaderPtr loader, + rmw_qos_profile_t custom_qos, + rclcpp::PublisherOptions options = rclcpp::PublisherOptions()); /*! * \brief Returns the number of subscribers that are currently connected to * this Publisher. @@ -122,6 +130,12 @@ class Publisher bool operator==(const Publisher & rhs) const {return impl_ == rhs.impl_;} private: + Publisher( + const std::string & base_topic, + PubLoaderPtr loader, + rmw_qos_profile_t custom_qos, + rclcpp::PublisherOptions options); + struct Impl; std::shared_ptr impl_; }; diff --git a/image_transport/include/image_transport/subscriber.hpp b/image_transport/include/image_transport/subscriber.hpp index af45e1bf..757e8e9f 100644 --- a/image_transport/include/image_transport/subscriber.hpp +++ b/image_transport/include/image_transport/subscriber.hpp @@ -34,6 +34,7 @@ #include #include "rclcpp/node.hpp" +#include "rclcpp_lifecycle/lifecycle_node.hpp" #include "sensor_msgs/msg/image.hpp" #include "image_transport/exception.hpp" @@ -76,6 +77,16 @@ class Subscriber rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::SubscriptionOptions options = rclcpp::SubscriptionOptions()); + IMAGE_TRANSPORT_PUBLIC + Subscriber( + rclcpp_lifecycle::LifecycleNode::SharedPtr node, + const std::string & base_topic, + const Callback & callback, + SubLoaderPtr loader, + const std::string & transport, + rmw_qos_profile_t custom_qos = rmw_qos_profile_default, + rclcpp::SubscriptionOptions options = rclcpp::SubscriptionOptions()); + /** * \brief Returns the base image topic. * @@ -113,6 +124,13 @@ class Subscriber bool operator==(const Subscriber & rhs) const {return impl_ == rhs.impl_;} private: + Subscriber( + const std::string & base_topic, + const Callback & callback, + const std::string & transport, + rmw_qos_profile_t custom_qos, + rclcpp::SubscriptionOptions options); + struct Impl; std::shared_ptr impl_; }; diff --git a/image_transport/include/image_transport/subscriber_plugin.hpp b/image_transport/include/image_transport/subscriber_plugin.hpp index 95e5856b..02ae629c 100644 --- a/image_transport/include/image_transport/subscriber_plugin.hpp +++ b/image_transport/include/image_transport/subscriber_plugin.hpp @@ -71,11 +71,34 @@ class IMAGE_TRANSPORT_PUBLIC SubscriberPlugin rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::SubscriptionOptions options = rclcpp::SubscriptionOptions()) { - if (impl_) { - throw std::runtime_error("advertise has been called previously!"); + if (!impl_) { + impl_ = std::make_unique(); + } + if (impl_->lifecycle_node_) { + throw std::runtime_error("subscribe has been called previously with a lifecycle node!"); + } + if (!impl_->node_) { + impl_->node_ = node; + } + + return subscribeImpl(base_topic, callback, custom_qos, options); + } + + void subscribe( + rclcpp_lifecycle::LifecycleNode::SharedPtr node, const std::string & base_topic, + const Callback & callback, + rmw_qos_profile_t custom_qos = rmw_qos_profile_default, + rclcpp::SubscriptionOptions options = rclcpp::SubscriptionOptions()) + { + if (!impl_) { + impl_ = std::make_unique(); + } + if (impl_->node_) { + throw std::runtime_error("subscribe has been called previously with a standard node!"); + } + if (!impl_->lifecycle_node_) { + impl_->lifecycle_node_ = node; } - impl_ = std::make_unique(); - impl_->node_ = node; return subscribeImpl(base_topic, callback, custom_qos, options); } @@ -95,6 +118,18 @@ class IMAGE_TRANSPORT_PUBLIC SubscriberPlugin custom_qos, options); } + void subscribe( + rclcpp_lifecycle::LifecycleNode::SharedPtr node, const std::string & base_topic, + void (* fp)(const sensor_msgs::msg::Image::ConstSharedPtr &), + rmw_qos_profile_t custom_qos = rmw_qos_profile_default, + rclcpp::SubscriptionOptions options = rclcpp::SubscriptionOptions()) + { + return subscribe( + node, base_topic, + std::function(fp), + custom_qos, options); + } + /** * \brief Subscribe to an image topic, version for class member function with bare pointer. */ @@ -110,6 +145,18 @@ class IMAGE_TRANSPORT_PUBLIC SubscriberPlugin std::bind(fp, obj, std::placeholders::_1), custom_qos, options); } + template + void subscribe( + rclcpp_lifecycle::LifecycleNode::SharedPtr node, const std::string & base_topic, + void (T::* fp)(const sensor_msgs::msg::Image::ConstSharedPtr &), T * obj, + rmw_qos_profile_t custom_qos = rmw_qos_profile_default, + rclcpp::SubscriptionOptions options = rclcpp::SubscriptionOptions()) + { + return subscribe( + node, base_topic, + std::bind(fp, obj, std::placeholders::_1), custom_qos, options); + } + /** * \brief Subscribe to an image topic, version for class member function with shared_ptr. */ @@ -125,6 +172,18 @@ class IMAGE_TRANSPORT_PUBLIC SubscriberPlugin std::bind(fp, obj, std::placeholders::_1), custom_qos); } + template + void subscribe( + rclcpp_lifecycle::LifecycleNode::SharedPtr node, const std::string & base_topic, + void (T::* fp)(const sensor_msgs::msg::Image::ConstSharedPtr &), + std::shared_ptr & obj, + rmw_qos_profile_t custom_qos = rmw_qos_profile_default) + { + return subscribe( + node, base_topic, + std::bind(fp, obj, std::placeholders::_1), custom_qos); + } + bool get_node(rclcpp::Node::SharedPtr node) const { if (impl_ && impl_->node_) { node = impl_->node_; diff --git a/image_transport/src/publisher.cpp b/image_transport/src/publisher.cpp index 13048c5e..8bcae088 100644 --- a/image_transport/src/publisher.cpp +++ b/image_transport/src/publisher.cpp @@ -49,7 +49,15 @@ namespace image_transport struct Publisher::Impl { explicit Impl(rclcpp::Node::SharedPtr node) - : logger_(node->get_logger()), + : node_(node), + logger_(node->get_logger()), + unadvertised_(false) + { + } + + explicit Impl(rclcpp_lifecycle::LifecycleNode::SharedPtr node) + : lifecycle_node_(node), + logger_(node->get_logger()), unadvertised_(false) { } @@ -89,6 +97,8 @@ struct Publisher::Impl } } + rclcpp::Node::SharedPtr node_; + rclcpp_lifecycle::LifecycleNode::SharedPtr lifecycle_node_; rclcpp::Logger logger_; std::string base_topic_; PubLoaderPtr loader_; @@ -102,15 +112,43 @@ Publisher::Publisher( rclcpp::PublisherOptions options) : impl_(std::make_shared(node)) { + Publisher(base_topic, loader, custom_qos, options); +} + +Publisher::Publisher( + rclcpp_lifecycle::LifecycleNode::SharedPtr node, const std::string & base_topic, + PubLoaderPtr loader, rmw_qos_profile_t custom_qos, + rclcpp::PublisherOptions options) +: impl_(std::make_shared(node)) +{ + Publisher(base_topic, loader, custom_qos, options); +} + +Publisher::Publisher( + const std::string & base_topic, + PubLoaderPtr loader, rmw_qos_profile_t custom_qos, + rclcpp::PublisherOptions options) +{ + if (!impl_) + { + throw std::runtime_error("impl is not constructed!"); + } // Resolve the name explicitly because otherwise the compressed topics don't remap // properly (#3652). - std::string image_topic = rclcpp::expand_topic_or_service_name( - base_topic, - node->get_name(), node->get_namespace()); + std::string image_topic; + size_t ns_len; + if (impl_->node_) { + image_topic = rclcpp::expand_topic_or_service_name( + base_topic, impl_->node_->get_name(), impl_->node_->get_namespace()); + ns_len = impl_->node_->get_effective_namespace().length(); + } else { + image_topic = rclcpp::expand_topic_or_service_name( + base_topic, impl_->lifecycle_node_->get_name(), impl_->lifecycle_node_->get_namespace()); + ns_len = strlen(impl_->lifecycle_node_->get_namespace()); + } impl_->base_topic_ = image_topic; impl_->loader_ = loader; - auto ns_len = node->get_effective_namespace().length(); std::string param_base_name = image_topic.substr(ns_len); std::replace(param_base_name.begin(), param_base_name.end(), '/', '.'); if (param_base_name.front() == '.') { @@ -123,16 +161,28 @@ Publisher::Publisher( all_transport_names.emplace_back(erase_last_copy(lookup_name, "_pub")); } try { - allowlist_vec = node->declare_parameter>( - param_base_name + ".enable_pub_plugins", all_transport_names); + if (impl_->node_) { + allowlist_vec = impl_->node_->declare_parameter>( + param_base_name + ".enable_pub_plugins", all_transport_names); + } else { + allowlist_vec = impl_->lifecycle_node_->declare_parameter>( + param_base_name + ".enable_pub_plugins", all_transport_names); + } } catch (const rclcpp::exceptions::ParameterAlreadyDeclaredException &) { RCLCPP_DEBUG_STREAM( - node->get_logger(), param_base_name << ".enable_pub_plugins" << " was previously declared" + impl_->logger_, param_base_name << ".enable_pub_plugins" << " was previously declared" ); - allowlist_vec = - node->get_parameter( - param_base_name + - ".enable_pub_plugins").get_value>(); + if (impl_->node_) { + allowlist_vec = + impl_->node_->get_parameter( + param_base_name + + ".enable_pub_plugins").get_value>(); + } else { + allowlist_vec = + impl_->lifecycle_node_->get_parameter( + param_base_name + + ".enable_pub_plugins").get_value>(); + } } for (size_t i = 0; i < allowlist_vec.size(); ++i) { allowlist.insert(allowlist_vec[i]); @@ -142,7 +192,11 @@ Publisher::Publisher( const auto & lookup_name = transport_name + "_pub"; try { auto pub = loader->createUniqueInstance(lookup_name); - pub->advertise(node, image_topic, custom_qos, options); + if (impl_->node_) { + pub->advertise(impl_->node_, image_topic, custom_qos, options); + } else { + pub->advertise(impl_->lifecycle_node_, image_topic, custom_qos, options); + } impl_->publishers_.push_back(std::move(pub)); } catch (const std::runtime_error & e) { RCLCPP_ERROR( diff --git a/image_transport/src/subscriber.cpp b/image_transport/src/subscriber.cpp index 26445f86..e07b0ee0 100644 --- a/image_transport/src/subscriber.cpp +++ b/image_transport/src/subscriber.cpp @@ -47,7 +47,16 @@ namespace image_transport struct Subscriber::Impl { Impl(rclcpp::Node::SharedPtr node, SubLoaderPtr loader) - : logger_(node->get_logger()), + : node_(node), + logger_(node->get_logger()), + loader_(loader), + unsubscribed_(false) + { + } + + explicit Impl(rclcpp_lifecycle::LifecycleNode::SharedPtr node, SubLoaderPtr loader) + : lifecycle_node_(node), + logger_(node->get_logger()), loader_(loader), unsubscribed_(false) { @@ -73,6 +82,8 @@ struct Subscriber::Impl } } + rclcpp::Node::SharedPtr node_; + rclcpp_lifecycle::LifecycleNode::SharedPtr lifecycle_node_; rclcpp::Logger logger_; std::string lookup_name_; SubLoaderPtr loader_; @@ -91,10 +102,37 @@ Subscriber::Subscriber( rclcpp::SubscriptionOptions options) : impl_(std::make_shared(node, loader)) { + Subscriber(base_topic, callback, transport, custom_qos, options); +} + +Subscriber::Subscriber( + rclcpp_lifecycle::LifecycleNode::SharedPtr node, + const std::string & base_topic, + const Callback & callback, + SubLoaderPtr loader, + const std::string & transport, + rmw_qos_profile_t custom_qos, + rclcpp::SubscriptionOptions options) +: impl_(std::make_shared(node, loader)) +{ + Subscriber(base_topic, callback, transport, custom_qos, options); +} + +Subscriber::Subscriber( + const std::string & base_topic, + const Callback & callback, + const std::string & transport, + rmw_qos_profile_t custom_qos, + rclcpp::SubscriptionOptions options) +{ + if (!impl_) + { + throw std::runtime_error("impl is not constructed!"); + } // Load the plugin for the chosen transport. impl_->lookup_name_ = SubscriberPlugin::getLookupName(transport); try { - impl_->subscriber_ = loader->createSharedInstance(impl_->lookup_name_); + impl_->subscriber_ = impl_->loader_->createSharedInstance(impl_->lookup_name_); } catch (pluginlib::PluginlibException & e) { throw TransportLoadException(impl_->lookup_name_, e.what()); } @@ -108,7 +146,7 @@ Subscriber::Subscriber( if (found != std::string::npos) { std::string transport = clean_topic.substr(found + 1); std::string plugin_name = SubscriberPlugin::getLookupName(transport); - std::vector plugins = loader->getDeclaredClasses(); + std::vector plugins = impl_->loader_->getDeclaredClasses(); if (std::find(plugins.begin(), plugins.end(), plugin_name) != plugins.end()) { std::string real_base_topic = clean_topic.substr(0, found); @@ -125,7 +163,11 @@ Subscriber::Subscriber( // Tell plugin to subscribe. RCLCPP_DEBUG(impl_->logger_, "Subscribing to: %s\n", base_topic.c_str()); - impl_->subscriber_->subscribe(node, base_topic, callback, custom_qos, options); + if (impl_->node_) { + impl_->subscriber_->subscribe(impl_->node_, base_topic, callback, custom_qos, options); + } else { + impl_->subscriber_->subscribe(impl_->lifecycle_node_, base_topic, callback, custom_qos, options); + } } std::string Subscriber::getTopic() const From 670786061c1a9bd6b6a7e3e4c3bbe8615b5eea52 Mon Sep 17 00:00:00 2001 From: Benjamin-Tan Date: Sat, 6 Apr 2024 21:40:04 +0800 Subject: [PATCH 03/14] Extend lifecycle node to camera publisher, camera subscriber, image transport free function, subscriber filter, transport hints --- .../image_transport/camera_publisher.hpp | 13 ++ .../image_transport/camera_subscriber.hpp | 15 +++ .../image_transport/image_transport.hpp | 34 ++++++ .../image_transport/subscriber_filter.hpp | 23 ++++ .../image_transport/transport_hints.hpp | 12 +- image_transport/src/camera_publisher.cpp | 56 ++++++++- image_transport/src/camera_subscriber.cpp | 110 ++++++++++++++--- image_transport/src/image_transport.cpp | 115 +++++++++++++++--- 8 files changed, 340 insertions(+), 38 deletions(-) diff --git a/image_transport/include/image_transport/camera_publisher.hpp b/image_transport/include/image_transport/camera_publisher.hpp index 4269b738..2feb6166 100644 --- a/image_transport/include/image_transport/camera_publisher.hpp +++ b/image_transport/include/image_transport/camera_publisher.hpp @@ -34,6 +34,7 @@ #include "rclcpp/macros.hpp" #include "rclcpp/node.hpp" +#include "rclcpp_lifecycle/lifecycle_node.hpp" #include "sensor_msgs/msg/image.hpp" #include "sensor_msgs/msg/camera_info.hpp" @@ -74,6 +75,13 @@ class CameraPublisher rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::PublisherOptions = rclcpp::PublisherOptions()); + IMAGE_TRANSPORT_PUBLIC + CameraPublisher( + rclcpp_lifecycle::LifecycleNode::SharedPtr node, + const std::string & base_topic, + rmw_qos_profile_t custom_qos = rmw_qos_profile_default, + rclcpp::PublisherOptions = rclcpp::PublisherOptions()); + /*! * \brief Returns the number of subscribers that are currently connected to * this CameraPublisher. @@ -142,6 +150,11 @@ class CameraPublisher bool operator==(const CameraPublisher & rhs) const {return impl_ == rhs.impl_;} private: + CameraPublisher( + const std::string & base_topic, + rmw_qos_profile_t custom_qos, + rclcpp::PublisherOptions options); + struct Impl; std::shared_ptr impl_; }; diff --git a/image_transport/include/image_transport/camera_subscriber.hpp b/image_transport/include/image_transport/camera_subscriber.hpp index 4ab8f1ce..41068574 100644 --- a/image_transport/include/image_transport/camera_subscriber.hpp +++ b/image_transport/include/image_transport/camera_subscriber.hpp @@ -34,6 +34,7 @@ #include #include "rclcpp/node.hpp" +#include "rclcpp_lifecycle/lifecycle_node.hpp" #include "sensor_msgs/msg/camera_info.hpp" #include "sensor_msgs/msg/image.hpp" @@ -77,6 +78,14 @@ class CameraSubscriber const std::string & transport, rmw_qos_profile_t = rmw_qos_profile_default); + IMAGE_TRANSPORT_PUBLIC + CameraSubscriber( + rclcpp_lifecycle::LifecycleNode::SharedPtr node, + const std::string & base_topic, + const Callback & callback, + const std::string & transport, + rmw_qos_profile_t = rmw_qos_profile_default); + /** * \brief Get the base topic (on which the raw image is published). */ @@ -120,6 +129,12 @@ class CameraSubscriber bool operator==(const CameraSubscriber & rhs) const {return impl_ == rhs.impl_;} private: + CameraSubscriber( + const std::string & base_topic, + const Callback & callback, + const std::string & transport, + rmw_qos_profile_t custom_qos); + struct Impl; std::shared_ptr impl_; }; diff --git a/image_transport/include/image_transport/image_transport.hpp b/image_transport/include/image_transport/image_transport.hpp index 2a39dd9c..70b24f63 100644 --- a/image_transport/include/image_transport/image_transport.hpp +++ b/image_transport/include/image_transport/image_transport.hpp @@ -56,6 +56,13 @@ Publisher create_publisher( rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::PublisherOptions options = rclcpp::PublisherOptions()); +IMAGE_TRANSPORT_PUBLIC +Publisher create_publisher( + rclcpp_lifecycle::LifecycleNode::SharedPtr node, + const std::string & base_topic, + rmw_qos_profile_t custom_qos = rmw_qos_profile_default, + rclcpp::PublisherOptions options = rclcpp::PublisherOptions()); + /** * \brief Subscribe to an image topic, free function version. */ @@ -68,6 +75,15 @@ Subscriber create_subscription( rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::SubscriptionOptions options = rclcpp::SubscriptionOptions()); +IMAGE_TRANSPORT_PUBLIC +Subscriber create_subscription( + rclcpp_lifecycle::LifecycleNode::SharedPtr node, + const std::string & base_topic, + const Subscriber::Callback & callback, + const std::string & transport, + rmw_qos_profile_t custom_qos = rmw_qos_profile_default, + rclcpp::SubscriptionOptions options = rclcpp::SubscriptionOptions()); + /*! * \brief Advertise a camera, free function version. */ @@ -78,6 +94,13 @@ CameraPublisher create_camera_publisher( rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::PublisherOptions pub_options = rclcpp::PublisherOptions()); +IMAGE_TRANSPORT_PUBLIC +CameraPublisher create_camera_publisher( + rclcpp_lifecycle::LifecycleNode::SharedPtr node, + const std::string & base_topic, + rmw_qos_profile_t custom_qos = rmw_qos_profile_default, + rclcpp::PublisherOptions pub_options = rclcpp::PublisherOptions()); + /*! * \brief Subscribe to a camera, free function version. */ @@ -89,6 +112,14 @@ CameraSubscriber create_camera_subscription( const std::string & transport, rmw_qos_profile_t custom_qos = rmw_qos_profile_default); +IMAGE_TRANSPORT_PUBLIC +CameraSubscriber create_camera_subscription( + rclcpp_lifecycle::LifecycleNode::SharedPtr node, + const std::string & base_topic, + const CameraSubscriber::Callback & callback, + const std::string & transport, + rmw_qos_profile_t custom_qos = rmw_qos_profile_default); + IMAGE_TRANSPORT_PUBLIC std::vector getDeclaredTransports(); @@ -112,6 +143,9 @@ class ImageTransport IMAGE_TRANSPORT_PUBLIC explicit ImageTransport(rclcpp::Node::SharedPtr node); + IMAGE_TRANSPORT_PUBLIC + explicit ImageTransport(rclcpp_lifecycle::LifecycleNode::SharedPtr node); + IMAGE_TRANSPORT_PUBLIC ~ImageTransport(); diff --git a/image_transport/include/image_transport/subscriber_filter.hpp b/image_transport/include/image_transport/subscriber_filter.hpp index 2a588dfc..0050df43 100644 --- a/image_transport/include/image_transport/subscriber_filter.hpp +++ b/image_transport/include/image_transport/subscriber_filter.hpp @@ -83,6 +83,14 @@ class SubscriberFilter : public message_filters::SimpleFilter #include "rclcpp/node.hpp" +#include "rclcpp_lifecycle/lifecycle_node.hpp" #include "image_transport/visibility_control.hpp" @@ -59,7 +60,16 @@ class TransportHints */ IMAGE_TRANSPORT_PUBLIC TransportHints( - const rclcpp::Node * node, + const rclcpp::Node::SharedPtr node, + const std::string & default_transport = "raw", + const std::string & parameter_name = "image_transport") + { + node->get_parameter_or(parameter_name, transport_, default_transport); + } + + IMAGE_TRANSPORT_PUBLIC + TransportHints( + const rclcpp_lifecycle::LifecycleNode::SharedPtr node, const std::string & default_transport = "raw", const std::string & parameter_name = "image_transport") { diff --git a/image_transport/src/camera_publisher.cpp b/image_transport/src/camera_publisher.cpp index f51fcb45..12f50c3f 100644 --- a/image_transport/src/camera_publisher.cpp +++ b/image_transport/src/camera_publisher.cpp @@ -44,7 +44,15 @@ namespace image_transport struct CameraPublisher::Impl { explicit Impl(rclcpp::Node::SharedPtr node) - : logger_(node->get_logger()), + : node_(node), + logger_(node->get_logger()), + unadvertised_(false) + { + } + + explicit Impl(rclcpp_lifecycle::LifecycleNode::SharedPtr node) + : lifecycle_node_(node), + logger_(node->get_logger()), unadvertised_(false) { } @@ -68,6 +76,8 @@ struct CameraPublisher::Impl } } + rclcpp::Node::SharedPtr node_; + rclcpp_lifecycle::LifecycleNode::SharedPtr lifecycle_node_; rclcpp::Logger logger_; Publisher image_pub_; rclcpp::Publisher::SharedPtr info_pub_; @@ -81,16 +91,50 @@ CameraPublisher::CameraPublisher( rclcpp::PublisherOptions pub_options) : impl_(std::make_shared(node)) { + CameraPublisher(base_topic, custom_qos, pub_options); +} + +CameraPublisher::CameraPublisher( + rclcpp_lifecycle::LifecycleNode::SharedPtr node, + const std::string & base_topic, + rmw_qos_profile_t custom_qos, + rclcpp::PublisherOptions pub_options) +: impl_(std::make_shared(node)) +{ + CameraPublisher(base_topic, custom_qos, pub_options); +} + +CameraPublisher::CameraPublisher( + const std::string & base_topic, + rmw_qos_profile_t custom_qos, + rclcpp::PublisherOptions pub_options) +{ + if (!impl_) + { + throw std::runtime_error("impl is not constructed!"); + } // Explicitly resolve name here so we compute the correct CameraInfo topic when the // image topic is remapped (#4539). - std::string image_topic = rclcpp::expand_topic_or_service_name( - base_topic, - node->get_name(), node->get_namespace()); + std::string image_topic; + if (impl_->node_) { + image_topic = rclcpp::expand_topic_or_service_name( + base_topic, + impl_->node_->get_name(), impl_->node_->get_namespace()); + } else { + image_topic = rclcpp::expand_topic_or_service_name( + base_topic, + impl_->lifecycle_node_->get_name(), impl_->lifecycle_node_->get_namespace()); + } std::string info_topic = getCameraInfoTopic(image_topic); auto qos = rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(custom_qos), custom_qos); - impl_->image_pub_ = image_transport::create_publisher(node, image_topic, custom_qos, pub_options); - impl_->info_pub_ = node->create_publisher(info_topic, qos); + if (impl_->node_) { + impl_->image_pub_ = image_transport::create_publisher(impl_->node_, image_topic, custom_qos, pub_options); + impl_->info_pub_ = impl_->node_->create_publisher(info_topic, qos); + } else { + impl_->image_pub_ = image_transport::create_publisher(impl_->lifecycle_node_, image_topic, custom_qos, pub_options); + impl_->info_pub_ = impl_->lifecycle_node_->create_publisher(info_topic, qos); + } } size_t CameraPublisher::getNumSubscribers() const diff --git a/image_transport/src/camera_subscriber.cpp b/image_transport/src/camera_subscriber.cpp index 99d5dce9..d7df6591 100644 --- a/image_transport/src/camera_subscriber.cpp +++ b/image_transport/src/camera_subscriber.cpp @@ -52,7 +52,17 @@ struct CameraSubscriber::Impl using TimeSync = message_filters::TimeSynchronizer; explicit Impl(rclcpp::Node::SharedPtr node) - : logger_(node->get_logger()), + : node_(node), + logger_(node->get_logger()), + sync_(10), + unsubscribed_(false), + image_received_(0), info_received_(0), both_received_(0) + { + } + + explicit Impl(rclcpp_lifecycle::LifecycleNode::SharedPtr node) + : lifecycle_node_(node), + logger_(node->get_logger()), sync_(10), unsubscribed_(false), image_received_(0), info_received_(0), both_received_(0) @@ -74,7 +84,11 @@ struct CameraSubscriber::Impl if (!unsubscribed_) { unsubscribed_ = true; image_sub_.unsubscribe(); - info_sub_.unsubscribe(); + if (node_) { + info_sub_.unsubscribe(); + } else { + lifecycle_info_sub_.unsubscribe(); + } } } @@ -82,6 +96,12 @@ struct CameraSubscriber::Impl { int threshold = 3 * both_received_; if (image_received_ > threshold || info_received_ > threshold) { + std::string info_topic; + if (node_) { + info_topic = info_sub_.getTopic(); + } else { + info_topic = lifecycle_info_sub_.getTopic(); + } RCLCPP_WARN( logger_, "[image_transport] Topics '%s' and '%s' do not appear to be synchronized. " @@ -89,15 +109,18 @@ struct CameraSubscriber::Impl "\tImage messages received: %d\n" "\tCameraInfo messages received: %d\n" "\tSynchronized pairs: %d", - image_sub_.getTopic().c_str(), info_sub_.getTopic().c_str(), + image_sub_.getTopic().c_str(), info_topic.c_str(), image_received_, info_received_, both_received_); } image_received_ = info_received_ = both_received_ = 0; } + rclcpp::Node::SharedPtr node_; + rclcpp_lifecycle::LifecycleNode::SharedPtr lifecycle_node_; rclcpp::Logger logger_; SubscriberFilter image_sub_; message_filters::Subscriber info_sub_; + message_filters::Subscriber lifecycle_info_sub_; TimeSync sync_; bool unsubscribed_; @@ -114,27 +137,71 @@ CameraSubscriber::CameraSubscriber( rmw_qos_profile_t custom_qos) : impl_(std::make_shared(node)) { + CameraSubscriber(base_topic, callback, transport, custom_qos); +} + +CameraSubscriber::CameraSubscriber( + rclcpp_lifecycle::LifecycleNode::SharedPtr node, + const std::string & base_topic, + const Callback & callback, + const std::string & transport, + rmw_qos_profile_t custom_qos) +: impl_(std::make_shared(node)) +{ + CameraSubscriber(base_topic, callback, transport, custom_qos); +} + +CameraSubscriber::CameraSubscriber( + const std::string & base_topic, + const Callback & callback, + const std::string & transport, + rmw_qos_profile_t custom_qos) +{ + if (!impl_) + { + throw std::runtime_error("impl is not constructed!"); + } // Must explicitly remap the image topic since we then do some string manipulation on it // to figure out the sibling camera_info topic. - std::string image_topic = rclcpp::expand_topic_or_service_name( - base_topic, - node->get_name(), node->get_namespace()); + std::string image_topic; + if (impl_->node_) { + image_topic = rclcpp::expand_topic_or_service_name( + base_topic, + impl_->node_->get_name(), impl_->node_->get_namespace()); + } else { + image_topic = rclcpp::expand_topic_or_service_name( + base_topic, + impl_->lifecycle_node_->get_name(), impl_->lifecycle_node_->get_namespace()); + } std::string info_topic = getCameraInfoTopic(image_topic); - impl_->image_sub_.subscribe(node, image_topic, transport, custom_qos); - impl_->info_sub_.subscribe(node, info_topic, custom_qos); + if (impl_->node_) { + impl_->image_sub_.subscribe(impl_->node_, image_topic, transport, custom_qos); + impl_->info_sub_.subscribe(impl_->node_, info_topic, custom_qos); + impl_->sync_.connectInput(impl_->image_sub_, impl_->info_sub_); + impl_->info_sub_.registerCallback(std::bind(increment, &impl_->info_received_)); + } else { + impl_->image_sub_.subscribe(impl_->lifecycle_node_, image_topic, transport, custom_qos); + impl_->lifecycle_info_sub_.subscribe(impl_->lifecycle_node_, info_topic, custom_qos); + impl_->sync_.connectInput(impl_->image_sub_, impl_->lifecycle_info_sub_); + impl_->lifecycle_info_sub_.registerCallback(std::bind(increment, &impl_->info_received_)); + } - impl_->sync_.connectInput(impl_->image_sub_, impl_->info_sub_); impl_->sync_.registerCallback(std::bind(callback, std::placeholders::_1, std::placeholders::_2)); // Complain every 10s if it appears that the image and info topics are not synchronized impl_->image_sub_.registerCallback(std::bind(increment, &impl_->image_received_)); - impl_->info_sub_.registerCallback(std::bind(increment, &impl_->info_received_)); impl_->sync_.registerCallback(std::bind(increment, &impl_->both_received_)); - impl_->check_synced_timer_ = node->create_wall_timer( - std::chrono::seconds(1), - std::bind(&Impl::checkImagesSynchronized, impl_.get())); + if (impl_->node_) { + impl_->check_synced_timer_ = impl_->node_->create_wall_timer( + std::chrono::seconds(1), + std::bind(&Impl::checkImagesSynchronized, impl_.get())); + } else { + impl_->check_synced_timer_ = impl_->lifecycle_node_->create_wall_timer( + std::chrono::seconds(1), + std::bind(&Impl::checkImagesSynchronized, impl_.get())); + } } std::string CameraSubscriber::getTopic() const @@ -145,16 +212,29 @@ std::string CameraSubscriber::getTopic() const std::string CameraSubscriber::getInfoTopic() const { - if (impl_) {return impl_->info_sub_.getSubscriber()->get_topic_name();} + if (impl_) { + if (impl_->node_) { + return impl_->info_sub_.getSubscriber()->get_topic_name(); + } else { + return impl_->lifecycle_info_sub_.getSubscriber()->get_topic_name(); + } + } return std::string(); } size_t CameraSubscriber::getNumPublishers() const { if (impl_) { + size_t info_pub_count; + if (impl_->node_) { + info_pub_count = impl_->info_sub_.getSubscriber()->get_publisher_count(); + } else { + info_pub_count = impl_->lifecycle_info_sub_.getSubscriber()->get_publisher_count(); + } + return std::max( impl_->image_sub_.getSubscriber().getNumPublishers(), - impl_->info_sub_.getSubscriber()->get_publisher_count()); + info_pub_count); } return 0; } diff --git a/image_transport/src/image_transport.cpp b/image_transport/src/image_transport.cpp index 5b1545b3..5d83eb95 100644 --- a/image_transport/src/image_transport.cpp +++ b/image_transport/src/image_transport.cpp @@ -65,6 +65,15 @@ Publisher create_publisher( return Publisher(node, base_topic, kImpl->pub_loader_, custom_qos, options); } +Publisher create_publisher( + rclcpp_lifecycle::LifecycleNode::SharedPtr node, + const std::string & base_topic, + rmw_qos_profile_t custom_qos, + rclcpp::PublisherOptions options) +{ + return Publisher(node, base_topic, kImpl->pub_loader_, custom_qos, options); +} + Subscriber create_subscription( rclcpp::Node::SharedPtr node, const std::string & base_topic, @@ -76,6 +85,17 @@ Subscriber create_subscription( return Subscriber(node, base_topic, callback, kImpl->sub_loader_, transport, custom_qos, options); } +Subscriber create_subscription( + rclcpp_lifecycle::LifecycleNode::SharedPtr node, + const std::string & base_topic, + const Subscriber::Callback & callback, + const std::string & transport, + rmw_qos_profile_t custom_qos, + rclcpp::SubscriptionOptions options) +{ + return Subscriber(node, base_topic, callback, kImpl->sub_loader_, transport, custom_qos, options); +} + CameraPublisher create_camera_publisher( rclcpp::Node::SharedPtr node, const std::string & base_topic, @@ -85,6 +105,15 @@ CameraPublisher create_camera_publisher( return CameraPublisher(node, base_topic, custom_qos, pub_options); } +CameraPublisher create_camera_publisher( + rclcpp_lifecycle::LifecycleNode::SharedPtr node, + const std::string & base_topic, + rmw_qos_profile_t custom_qos, + rclcpp::PublisherOptions pub_options) +{ + return CameraPublisher(node, base_topic, custom_qos, pub_options); +} + CameraSubscriber create_camera_subscription( rclcpp::Node::SharedPtr node, const std::string & base_topic, @@ -95,6 +124,16 @@ CameraSubscriber create_camera_subscription( return CameraSubscriber(node, base_topic, callback, transport, custom_qos); } +CameraSubscriber create_camera_subscription( + rclcpp_lifecycle::LifecycleNode::SharedPtr node, + const std::string & base_topic, + const CameraSubscriber::Callback & callback, + const std::string & transport, + rmw_qos_profile_t custom_qos) +{ + return CameraSubscriber(node, base_topic, callback, transport, custom_qos); +} + std::vector getDeclaredTransports() { std::vector transports = kImpl->sub_loader_->getDeclaredClasses(); @@ -131,6 +170,7 @@ std::vector getLoadableTransports() struct ImageTransport::Impl { rclcpp::Node::SharedPtr node_; + rclcpp_lifecycle::LifecycleNode::SharedPtr lifecycle_node_; }; ImageTransport::ImageTransport(rclcpp::Node::SharedPtr node) @@ -139,6 +179,12 @@ ImageTransport::ImageTransport(rclcpp::Node::SharedPtr node) impl_->node_ = node; } +ImageTransport::ImageTransport(rclcpp_lifecycle::LifecycleNode::SharedPtr node) +: impl_(std::make_unique()) +{ + impl_->lifecycle_node_ = node; +} + ImageTransport::~ImageTransport() = default; Publisher ImageTransport::advertise(const std::string & base_topic, uint32_t queue_size, bool latch) @@ -147,7 +193,11 @@ Publisher ImageTransport::advertise(const std::string & base_topic, uint32_t que (void) latch; rmw_qos_profile_t custom_qos = rmw_qos_profile_default; custom_qos.depth = queue_size; - return create_publisher(impl_->node_, base_topic, custom_qos); + if (impl_->node_) { + return create_publisher(impl_->node_, base_topic, custom_qos); + } else { + return create_publisher(impl_->lifecycle_node_, base_topic, custom_qos); + } } Publisher ImageTransport::advertise( @@ -156,7 +206,11 @@ Publisher ImageTransport::advertise( { // TODO(ros2) implement when resolved: https://github.com/ros2/ros2/issues/464 (void) latch; - return create_publisher(impl_->node_, base_topic, custom_qos); + if (impl_->node_) { + return create_publisher(impl_->node_, base_topic, custom_qos); + } else { + return create_publisher(impl_->lifecycle_node_, base_topic, custom_qos); + } } Subscriber ImageTransport::subscribe( @@ -167,10 +221,17 @@ Subscriber ImageTransport::subscribe( const rclcpp::SubscriptionOptions options) { (void) tracked_object; - return create_subscription( - impl_->node_, base_topic, callback, - getTransportOrDefault(transport_hints), custom_qos, - options); + if (impl_->node_) { + return create_subscription( + impl_->node_, base_topic, callback, + getTransportOrDefault(transport_hints), custom_qos, + options); + } else { + return create_subscription( + impl_->lifecycle_node_, base_topic, callback, + getTransportOrDefault(transport_hints), custom_qos, + options); + } } Subscriber ImageTransport::subscribe( @@ -183,10 +244,17 @@ Subscriber ImageTransport::subscribe( (void) tracked_object; rmw_qos_profile_t custom_qos = rmw_qos_profile_default; custom_qos.depth = queue_size; - return create_subscription( - impl_->node_, base_topic, callback, - getTransportOrDefault(transport_hints), custom_qos, - options); + if (impl_->node_) { + return create_subscription( + impl_->node_, base_topic, callback, + getTransportOrDefault(transport_hints), custom_qos, + options); + } else { + return create_subscription( + impl_->lifecycle_node_, base_topic, callback, + getTransportOrDefault(transport_hints), custom_qos, + options); + } } CameraPublisher ImageTransport::advertiseCamera( @@ -197,7 +265,11 @@ CameraPublisher ImageTransport::advertiseCamera( (void) latch; rmw_qos_profile_t custom_qos = rmw_qos_profile_default; custom_qos.depth = queue_size; - return create_camera_publisher(impl_->node_, base_topic, custom_qos); + if (impl_->node_) { + return create_camera_publisher(impl_->node_, base_topic, custom_qos); + } else { + return create_camera_publisher(impl_->lifecycle_node_, base_topic, custom_qos); + } } CameraSubscriber ImageTransport::subscribeCamera( @@ -209,9 +281,15 @@ CameraSubscriber ImageTransport::subscribeCamera( (void) tracked_object; rmw_qos_profile_t custom_qos = rmw_qos_profile_default; custom_qos.depth = queue_size; - return create_camera_subscription( - impl_->node_, base_topic, callback, - getTransportOrDefault(transport_hints), custom_qos); + if (impl_->node_) { + return create_camera_subscription( + impl_->node_, base_topic, callback, + getTransportOrDefault(transport_hints), custom_qos); + } else { + return create_camera_subscription( + impl_->lifecycle_node_, base_topic, callback, + getTransportOrDefault(transport_hints), custom_qos); + } } std::vector ImageTransport::getDeclaredTransports() const @@ -228,8 +306,13 @@ std::string ImageTransport::getTransportOrDefault(const TransportHints * transpo { std::string ret; if (nullptr == transport_hints) { - TransportHints th(impl_->node_.get()); - ret = th.getTransport(); + if (impl_->node_) { + TransportHints th(impl_->node_); + ret = th.getTransport(); + } else { + TransportHints th(impl_->lifecycle_node_); + ret = th.getTransport(); + } } else { ret = transport_hints->getTransport(); } From ba5e59923548431533c2e1bef034a0700e5b3f4d Mon Sep 17 00:00:00 2001 From: Benjamin-Tan Date: Sat, 6 Apr 2024 22:45:00 +0800 Subject: [PATCH 04/14] Fix initialising and unit test --- image_transport/CMakeLists.txt | 2 +- .../include/image_transport/camera_publisher.hpp | 2 +- .../include/image_transport/camera_subscriber.hpp | 2 +- image_transport/include/image_transport/publisher.hpp | 2 +- .../include/image_transport/publisher_plugin.hpp | 4 ++-- .../include/image_transport/simple_publisher_plugin.hpp | 1 - image_transport/include/image_transport/subscriber.hpp | 2 +- .../include/image_transport/subscriber_plugin.hpp | 4 ++-- image_transport/package.xml | 1 + image_transport/src/camera_publisher.cpp | 6 +++--- image_transport/src/camera_subscriber.cpp | 6 +++--- image_transport/src/publisher.cpp | 6 +++--- image_transport/src/subscriber.cpp | 6 +++--- 13 files changed, 22 insertions(+), 22 deletions(-) diff --git a/image_transport/CMakeLists.txt b/image_transport/CMakeLists.txt index 55c1a4b0..158815cc 100644 --- a/image_transport/CMakeLists.txt +++ b/image_transport/CMakeLists.txt @@ -109,7 +109,7 @@ install(DIRECTORY include/ DESTINATION include/${PROJECT_NAME}) ament_export_targets(export_${PROJECT_NAME}) -ament_export_dependencies(message_filters rclcpp sensor_msgs pluginlib) +ament_export_dependencies(message_filters rclcpp rclcpp_lifecycle sensor_msgs pluginlib) if(BUILD_TESTING) find_package(ament_lint_auto REQUIRED) diff --git a/image_transport/include/image_transport/camera_publisher.hpp b/image_transport/include/image_transport/camera_publisher.hpp index 2feb6166..497a9d0c 100644 --- a/image_transport/include/image_transport/camera_publisher.hpp +++ b/image_transport/include/image_transport/camera_publisher.hpp @@ -150,7 +150,7 @@ class CameraPublisher bool operator==(const CameraPublisher & rhs) const {return impl_ == rhs.impl_;} private: - CameraPublisher( + void initialise( const std::string & base_topic, rmw_qos_profile_t custom_qos, rclcpp::PublisherOptions options); diff --git a/image_transport/include/image_transport/camera_subscriber.hpp b/image_transport/include/image_transport/camera_subscriber.hpp index 41068574..75ca133d 100644 --- a/image_transport/include/image_transport/camera_subscriber.hpp +++ b/image_transport/include/image_transport/camera_subscriber.hpp @@ -129,7 +129,7 @@ class CameraSubscriber bool operator==(const CameraSubscriber & rhs) const {return impl_ == rhs.impl_;} private: - CameraSubscriber( + void initialise( const std::string & base_topic, const Callback & callback, const std::string & transport, diff --git a/image_transport/include/image_transport/publisher.hpp b/image_transport/include/image_transport/publisher.hpp index c7b89343..d1967389 100644 --- a/image_transport/include/image_transport/publisher.hpp +++ b/image_transport/include/image_transport/publisher.hpp @@ -130,7 +130,7 @@ class Publisher bool operator==(const Publisher & rhs) const {return impl_ == rhs.impl_;} private: - Publisher( + void initialise( const std::string & base_topic, PubLoaderPtr loader, rmw_qos_profile_t custom_qos, diff --git a/image_transport/include/image_transport/publisher_plugin.hpp b/image_transport/include/image_transport/publisher_plugin.hpp index 8820f754..46b7e134 100644 --- a/image_transport/include/image_transport/publisher_plugin.hpp +++ b/image_transport/include/image_transport/publisher_plugin.hpp @@ -99,7 +99,7 @@ class PublisherPlugin advertiseImpl(base_topic, custom_qos, options); } - bool get_node(rclcpp::Node::SharedPtr node) const { + bool get_node(rclcpp::Node::SharedPtr & node) const { if (impl_ && impl_->node_) { node = impl_->node_; return true; @@ -107,7 +107,7 @@ class PublisherPlugin return false; } - bool get_node(rclcpp_lifecycle::LifecycleNode::SharedPtr node) const { + bool get_node(rclcpp_lifecycle::LifecycleNode::SharedPtr & node) const { if (impl_ && impl_->lifecycle_node_) { node = impl_->lifecycle_node_; return true; diff --git a/image_transport/include/image_transport/simple_publisher_plugin.hpp b/image_transport/include/image_transport/simple_publisher_plugin.hpp index 748d6ebe..a5d79823 100644 --- a/image_transport/include/image_transport/simple_publisher_plugin.hpp +++ b/image_transport/include/image_transport/simple_publisher_plugin.hpp @@ -105,7 +105,6 @@ class SimplePublisherPlugin : public PublisherPlugin { std::string transport_topic = getTopicToAdvertise(base_topic); auto qos = rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(custom_qos), custom_qos); - simple_impl_ = std::make_unique(); if (get_node(simple_impl_->node_)) { simple_impl_->logger_ = simple_impl_->node_->get_logger(); diff --git a/image_transport/include/image_transport/subscriber.hpp b/image_transport/include/image_transport/subscriber.hpp index 757e8e9f..1d6bad23 100644 --- a/image_transport/include/image_transport/subscriber.hpp +++ b/image_transport/include/image_transport/subscriber.hpp @@ -124,7 +124,7 @@ class Subscriber bool operator==(const Subscriber & rhs) const {return impl_ == rhs.impl_;} private: - Subscriber( + void initialise( const std::string & base_topic, const Callback & callback, const std::string & transport, diff --git a/image_transport/include/image_transport/subscriber_plugin.hpp b/image_transport/include/image_transport/subscriber_plugin.hpp index 02ae629c..feb4df21 100644 --- a/image_transport/include/image_transport/subscriber_plugin.hpp +++ b/image_transport/include/image_transport/subscriber_plugin.hpp @@ -184,7 +184,7 @@ class IMAGE_TRANSPORT_PUBLIC SubscriberPlugin std::bind(fp, obj, std::placeholders::_1), custom_qos); } - bool get_node(rclcpp::Node::SharedPtr node) const { + bool get_node(rclcpp::Node::SharedPtr & node) const { if (impl_ && impl_->node_) { node = impl_->node_; return true; @@ -192,7 +192,7 @@ class IMAGE_TRANSPORT_PUBLIC SubscriberPlugin return false; } - bool get_node(rclcpp_lifecycle::LifecycleNode::SharedPtr node) const { + bool get_node(rclcpp_lifecycle::LifecycleNode::SharedPtr & node) const { if (impl_ && impl_->lifecycle_node_) { node = impl_->lifecycle_node_; return true; diff --git a/image_transport/package.xml b/image_transport/package.xml index cd74c03f..f24029ae 100644 --- a/image_transport/package.xml +++ b/image_transport/package.xml @@ -26,6 +26,7 @@ message_filters pluginlib rclcpp + rclcpp_lifecycle rclcpp_components sensor_msgs diff --git a/image_transport/src/camera_publisher.cpp b/image_transport/src/camera_publisher.cpp index 12f50c3f..047aeb1a 100644 --- a/image_transport/src/camera_publisher.cpp +++ b/image_transport/src/camera_publisher.cpp @@ -91,7 +91,7 @@ CameraPublisher::CameraPublisher( rclcpp::PublisherOptions pub_options) : impl_(std::make_shared(node)) { - CameraPublisher(base_topic, custom_qos, pub_options); + initialise(base_topic, custom_qos, pub_options); } CameraPublisher::CameraPublisher( @@ -101,10 +101,10 @@ CameraPublisher::CameraPublisher( rclcpp::PublisherOptions pub_options) : impl_(std::make_shared(node)) { - CameraPublisher(base_topic, custom_qos, pub_options); + initialise(base_topic, custom_qos, pub_options); } -CameraPublisher::CameraPublisher( +void CameraPublisher::initialise( const std::string & base_topic, rmw_qos_profile_t custom_qos, rclcpp::PublisherOptions pub_options) diff --git a/image_transport/src/camera_subscriber.cpp b/image_transport/src/camera_subscriber.cpp index d7df6591..ddd4627a 100644 --- a/image_transport/src/camera_subscriber.cpp +++ b/image_transport/src/camera_subscriber.cpp @@ -137,7 +137,7 @@ CameraSubscriber::CameraSubscriber( rmw_qos_profile_t custom_qos) : impl_(std::make_shared(node)) { - CameraSubscriber(base_topic, callback, transport, custom_qos); + initialise(base_topic, callback, transport, custom_qos); } CameraSubscriber::CameraSubscriber( @@ -148,10 +148,10 @@ CameraSubscriber::CameraSubscriber( rmw_qos_profile_t custom_qos) : impl_(std::make_shared(node)) { - CameraSubscriber(base_topic, callback, transport, custom_qos); + initialise(base_topic, callback, transport, custom_qos); } -CameraSubscriber::CameraSubscriber( +void CameraSubscriber::initialise( const std::string & base_topic, const Callback & callback, const std::string & transport, diff --git a/image_transport/src/publisher.cpp b/image_transport/src/publisher.cpp index 8bcae088..a7fed44a 100644 --- a/image_transport/src/publisher.cpp +++ b/image_transport/src/publisher.cpp @@ -112,7 +112,7 @@ Publisher::Publisher( rclcpp::PublisherOptions options) : impl_(std::make_shared(node)) { - Publisher(base_topic, loader, custom_qos, options); + initialise(base_topic, loader, custom_qos, options); } Publisher::Publisher( @@ -121,10 +121,10 @@ Publisher::Publisher( rclcpp::PublisherOptions options) : impl_(std::make_shared(node)) { - Publisher(base_topic, loader, custom_qos, options); + initialise(base_topic, loader, custom_qos, options); } -Publisher::Publisher( +void Publisher::initialise( const std::string & base_topic, PubLoaderPtr loader, rmw_qos_profile_t custom_qos, rclcpp::PublisherOptions options) diff --git a/image_transport/src/subscriber.cpp b/image_transport/src/subscriber.cpp index e07b0ee0..bd13a618 100644 --- a/image_transport/src/subscriber.cpp +++ b/image_transport/src/subscriber.cpp @@ -102,7 +102,7 @@ Subscriber::Subscriber( rclcpp::SubscriptionOptions options) : impl_(std::make_shared(node, loader)) { - Subscriber(base_topic, callback, transport, custom_qos, options); + initialise(base_topic, callback, transport, custom_qos, options); } Subscriber::Subscriber( @@ -115,10 +115,10 @@ Subscriber::Subscriber( rclcpp::SubscriptionOptions options) : impl_(std::make_shared(node, loader)) { - Subscriber(base_topic, callback, transport, custom_qos, options); + initialise(base_topic, callback, transport, custom_qos, options); } -Subscriber::Subscriber( +void Subscriber::initialise( const std::string & base_topic, const Callback & callback, const std::string & transport, From 8eae072e0084b5a0f2f49fcaf2e3543d76e41230 Mon Sep 17 00:00:00 2001 From: Benjamin-Tan Date: Sat, 6 Apr 2024 22:49:39 +0800 Subject: [PATCH 05/14] Fix formatting and linting error --- .../include/image_transport/publisher_plugin.hpp | 7 +++++-- .../image_transport/simple_publisher_plugin.hpp | 8 +++++--- .../include/image_transport/subscriber_plugin.hpp | 6 ++++-- image_transport/src/camera_publisher.cpp | 15 +++++++++------ image_transport/src/camera_subscriber.cpp | 3 +-- image_transport/src/publisher.cpp | 5 ++--- image_transport/src/subscriber.cpp | 6 +++--- 7 files changed, 29 insertions(+), 21 deletions(-) diff --git a/image_transport/include/image_transport/publisher_plugin.hpp b/image_transport/include/image_transport/publisher_plugin.hpp index 46b7e134..57c78d68 100644 --- a/image_transport/include/image_transport/publisher_plugin.hpp +++ b/image_transport/include/image_transport/publisher_plugin.hpp @@ -31,6 +31,7 @@ #include #include +#include #include "rclcpp/node.hpp" #include "rclcpp_lifecycle/lifecycle_node.hpp" @@ -99,7 +100,8 @@ class PublisherPlugin advertiseImpl(base_topic, custom_qos, options); } - bool get_node(rclcpp::Node::SharedPtr & node) const { + bool get_node(rclcpp::Node::SharedPtr & node) const + { if (impl_ && impl_->node_) { node = impl_->node_; return true; @@ -107,7 +109,8 @@ class PublisherPlugin return false; } - bool get_node(rclcpp_lifecycle::LifecycleNode::SharedPtr & node) const { + bool get_node(rclcpp_lifecycle::LifecycleNode::SharedPtr & node) const + { if (impl_ && impl_->lifecycle_node_) { node = impl_->lifecycle_node_; return true; diff --git a/image_transport/include/image_transport/simple_publisher_plugin.hpp b/image_transport/include/image_transport/simple_publisher_plugin.hpp index a5d79823..9dedbbad 100644 --- a/image_transport/include/image_transport/simple_publisher_plugin.hpp +++ b/image_transport/include/image_transport/simple_publisher_plugin.hpp @@ -108,10 +108,12 @@ class SimplePublisherPlugin : public PublisherPlugin simple_impl_ = std::make_unique(); if (get_node(simple_impl_->node_)) { simple_impl_->logger_ = simple_impl_->node_->get_logger(); - simple_impl_->pub_ = simple_impl_->node_->template create_publisher(transport_topic, qos, options); + simple_impl_->pub_ = simple_impl_->node_->template create_publisher( + transport_topic, qos, options); } else if (get_node(simple_impl_->lifecycle_node_)) { simple_impl_->logger_ = simple_impl_->lifecycle_node_->get_logger(); - simple_impl_->pub_ = simple_impl_->lifecycle_node_->template create_publisher(transport_topic, qos, options); + simple_impl_->pub_ = simple_impl_->lifecycle_node_->template create_publisher( + transport_topic, qos, options); } else { throw std::runtime_error("Not a standard node or lifecycle node!"); } @@ -147,7 +149,7 @@ class SimplePublisherPlugin : public PublisherPlugin private: struct SimplePublisherPluginImpl { - explicit SimplePublisherPluginImpl() + SimplePublisherPluginImpl() : logger_(rclcpp::get_logger("simple_publisher_plugin_impl")) { } diff --git a/image_transport/include/image_transport/subscriber_plugin.hpp b/image_transport/include/image_transport/subscriber_plugin.hpp index feb4df21..71b18fdd 100644 --- a/image_transport/include/image_transport/subscriber_plugin.hpp +++ b/image_transport/include/image_transport/subscriber_plugin.hpp @@ -184,7 +184,8 @@ class IMAGE_TRANSPORT_PUBLIC SubscriberPlugin std::bind(fp, obj, std::placeholders::_1), custom_qos); } - bool get_node(rclcpp::Node::SharedPtr & node) const { + bool get_node(rclcpp::Node::SharedPtr & node) const + { if (impl_ && impl_->node_) { node = impl_->node_; return true; @@ -192,7 +193,8 @@ class IMAGE_TRANSPORT_PUBLIC SubscriberPlugin return false; } - bool get_node(rclcpp_lifecycle::LifecycleNode::SharedPtr & node) const { + bool get_node(rclcpp_lifecycle::LifecycleNode::SharedPtr & node) const + { if (impl_ && impl_->lifecycle_node_) { node = impl_->lifecycle_node_; return true; diff --git a/image_transport/src/camera_publisher.cpp b/image_transport/src/camera_publisher.cpp index 047aeb1a..8859fecb 100644 --- a/image_transport/src/camera_publisher.cpp +++ b/image_transport/src/camera_publisher.cpp @@ -109,8 +109,7 @@ void CameraPublisher::initialise( rmw_qos_profile_t custom_qos, rclcpp::PublisherOptions pub_options) { - if (!impl_) - { + if (!impl_) { throw std::runtime_error("impl is not constructed!"); } // Explicitly resolve name here so we compute the correct CameraInfo topic when the @@ -129,11 +128,15 @@ void CameraPublisher::initialise( auto qos = rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(custom_qos), custom_qos); if (impl_->node_) { - impl_->image_pub_ = image_transport::create_publisher(impl_->node_, image_topic, custom_qos, pub_options); - impl_->info_pub_ = impl_->node_->create_publisher(info_topic, qos); + impl_->image_pub_ = image_transport::create_publisher( + impl_->node_, image_topic, custom_qos, pub_options); + impl_->info_pub_ = + impl_->node_->create_publisher(info_topic, qos); } else { - impl_->image_pub_ = image_transport::create_publisher(impl_->lifecycle_node_, image_topic, custom_qos, pub_options); - impl_->info_pub_ = impl_->lifecycle_node_->create_publisher(info_topic, qos); + impl_->image_pub_ = image_transport::create_publisher( + impl_->lifecycle_node_, image_topic, custom_qos, pub_options); + impl_->info_pub_ = + impl_->lifecycle_node_->create_publisher(info_topic, qos); } } diff --git a/image_transport/src/camera_subscriber.cpp b/image_transport/src/camera_subscriber.cpp index ddd4627a..c0cf3023 100644 --- a/image_transport/src/camera_subscriber.cpp +++ b/image_transport/src/camera_subscriber.cpp @@ -157,8 +157,7 @@ void CameraSubscriber::initialise( const std::string & transport, rmw_qos_profile_t custom_qos) { - if (!impl_) - { + if (!impl_) { throw std::runtime_error("impl is not constructed!"); } // Must explicitly remap the image topic since we then do some string manipulation on it diff --git a/image_transport/src/publisher.cpp b/image_transport/src/publisher.cpp index a7fed44a..cd214a8e 100644 --- a/image_transport/src/publisher.cpp +++ b/image_transport/src/publisher.cpp @@ -129,8 +129,7 @@ void Publisher::initialise( PubLoaderPtr loader, rmw_qos_profile_t custom_qos, rclcpp::PublisherOptions options) { - if (!impl_) - { + if (!impl_) { throw std::runtime_error("impl is not constructed!"); } // Resolve the name explicitly because otherwise the compressed topics don't remap @@ -172,7 +171,7 @@ void Publisher::initialise( RCLCPP_DEBUG_STREAM( impl_->logger_, param_base_name << ".enable_pub_plugins" << " was previously declared" ); - if (impl_->node_) { + if (impl_->node_) { allowlist_vec = impl_->node_->get_parameter( param_base_name + diff --git a/image_transport/src/subscriber.cpp b/image_transport/src/subscriber.cpp index bd13a618..06886890 100644 --- a/image_transport/src/subscriber.cpp +++ b/image_transport/src/subscriber.cpp @@ -125,8 +125,7 @@ void Subscriber::initialise( rmw_qos_profile_t custom_qos, rclcpp::SubscriptionOptions options) { - if (!impl_) - { + if (!impl_) { throw std::runtime_error("impl is not constructed!"); } // Load the plugin for the chosen transport. @@ -166,7 +165,8 @@ void Subscriber::initialise( if (impl_->node_) { impl_->subscriber_->subscribe(impl_->node_, base_topic, callback, custom_qos, options); } else { - impl_->subscriber_->subscribe(impl_->lifecycle_node_, base_topic, callback, custom_qos, options); + impl_->subscriber_->subscribe( + impl_->lifecycle_node_, base_topic, callback, custom_qos, options); } } From a5706530301df987e092ee597f5d7f5d27826761 Mon Sep 17 00:00:00 2001 From: Benjamin-Tan Date: Sat, 6 Apr 2024 23:18:38 +0800 Subject: [PATCH 06/14] Add test for lifecycle node --- image_transport/CMakeLists.txt | 30 +++ image_transport/test/test_message_passing.cpp | 4 +- .../test/test_message_passing_lifecycle.cpp | 183 +++++++++++++++ .../test/test_publisher_lifecycle.cpp | 99 ++++++++ .../test/test_qos_override_lifecycle.cpp | 163 +++++++++++++ image_transport/test/test_remapping.cpp | 2 +- .../test/test_remapping_lifecycle.cpp | 130 +++++++++++ ..._single_subscriber_publisher_lifecycle.cpp | 88 +++++++ .../test/test_subscriber_lifecycle.cpp | 219 ++++++++++++++++++ image_transport/test/utils.hpp | 2 +- 10 files changed, 916 insertions(+), 4 deletions(-) create mode 100644 image_transport/test/test_message_passing_lifecycle.cpp create mode 100644 image_transport/test/test_publisher_lifecycle.cpp create mode 100644 image_transport/test/test_qos_override_lifecycle.cpp create mode 100644 image_transport/test/test_remapping_lifecycle.cpp create mode 100644 image_transport/test/test_single_subscriber_publisher_lifecycle.cpp create mode 100644 image_transport/test/test_subscriber_lifecycle.cpp diff --git a/image_transport/CMakeLists.txt b/image_transport/CMakeLists.txt index 158815cc..12054820 100644 --- a/image_transport/CMakeLists.txt +++ b/image_transport/CMakeLists.txt @@ -133,30 +133,60 @@ if(BUILD_TESTING) target_link_libraries(${PROJECT_NAME}-publisher ${PROJECT_NAME}) endif() + ament_add_gtest(${PROJECT_NAME}-publisher_lifecycle test/test_publisher_lifecycle.cpp) + if(TARGET ${PROJECT_NAME}-publisher_lifecycle) + target_link_libraries(${PROJECT_NAME}-publisher_lifecycle ${PROJECT_NAME}) + endif() + ament_add_gtest(${PROJECT_NAME}-subscriber test/test_subscriber.cpp) if(TARGET ${PROJECT_NAME}-subscriber) target_link_libraries(${PROJECT_NAME}-subscriber ${PROJECT_NAME}) endif() + ament_add_gtest(${PROJECT_NAME}-subscriber_lifecycle test/test_subscriber_lifecycle.cpp) + if(TARGET ${PROJECT_NAME}-subscriber_lifecycle) + target_link_libraries(${PROJECT_NAME}-subscriber_lifecycle ${PROJECT_NAME}) + endif() + ament_add_gtest(${PROJECT_NAME}-message_passing test/test_message_passing.cpp) if(TARGET ${PROJECT_NAME}-message_passing) target_link_libraries(${PROJECT_NAME}-message_passing ${PROJECT_NAME}) endif() + ament_add_gtest(${PROJECT_NAME}-message_passing_lifecycle test/test_message_passing_lifecycle.cpp) + if(TARGET ${PROJECT_NAME}-message_passing_lifecycle) + target_link_libraries(${PROJECT_NAME}-message_passing_lifecycle ${PROJECT_NAME}) + endif() + ament_add_gtest(${PROJECT_NAME}-remapping test/test_remapping.cpp) if(TARGET ${PROJECT_NAME}-remapping) target_link_libraries(${PROJECT_NAME}-remapping ${PROJECT_NAME}) endif() + ament_add_gtest(${PROJECT_NAME}-remapping_lifecycle test/test_remapping_lifecycle.cpp) + if(TARGET ${PROJECT_NAME}-remapping_lifecycle) + target_link_libraries(${PROJECT_NAME}-remapping_lifecycle ${PROJECT_NAME}) + endif() + ament_add_gtest(${PROJECT_NAME}-qos_override test/test_qos_override.cpp) if(TARGET ${PROJECT_NAME}-qos_override) target_link_libraries(${PROJECT_NAME}-qos_override ${PROJECT_NAME}) endif() + ament_add_gtest(${PROJECT_NAME}-qos_override_lifecycle test/test_qos_override_lifecycle.cpp) + if(TARGET ${PROJECT_NAME}-qos_override_lifecycle) + target_link_libraries(${PROJECT_NAME}-qos_override_lifecycle ${PROJECT_NAME}) + endif() + ament_add_gtest(${PROJECT_NAME}-single_subscriber_publisher test/test_single_subscriber_publisher.cpp) if(TARGET ${PROJECT_NAME}-single_subscriber_publisher) target_link_libraries(${PROJECT_NAME}-single_subscriber_publisher ${PROJECT_NAME}) endif() + + ament_add_gtest(${PROJECT_NAME}-single_subscriber_publisher_lifecycle test/test_single_subscriber_publisher_lifecycle.cpp) + if(TARGET ${PROJECT_NAME}-single_subscriber_publisher_lifecycle) + target_link_libraries(${PROJECT_NAME}-single_subscriber_publisher_lifecycle ${PROJECT_NAME}) + endif() endif() ament_package() diff --git a/image_transport/test/test_message_passing.cpp b/image_transport/test/test_message_passing.cpp index 87dbd4b3..e5a0c8de 100644 --- a/image_transport/test/test_message_passing.cpp +++ b/image_transport/test/test_message_passing.cpp @@ -81,7 +81,7 @@ TEST_F(MessagePassingTesting, one_message_passing) auto sub = image_transport::create_subscription(node_, "camera/image", imageCallback, "raw"); - test_rclcpp::wait_for_subscriber(node_, sub.getTopic()); + test_rclcpp::wait_for_subscriber(node_->get_node_graph_interface(), sub.getTopic()); ASSERT_EQ(0, total_images_received); ASSERT_EQ(1u, pub.getNumSubscribers()); @@ -126,7 +126,7 @@ TEST_F(MessagePassingTesting, one_camera_message_passing) "raw" ); - test_rclcpp::wait_for_subscriber(node_, sub.getTopic()); + test_rclcpp::wait_for_subscriber(node_->get_node_graph_interface(), sub.getTopic()); ASSERT_EQ(0, total_images_received); executor.spin_node_some(node_); diff --git a/image_transport/test/test_message_passing_lifecycle.cpp b/image_transport/test/test_message_passing_lifecycle.cpp new file mode 100644 index 00000000..a1f4a888 --- /dev/null +++ b/image_transport/test/test_message_passing_lifecycle.cpp @@ -0,0 +1,183 @@ +// Copyright (c) 2018 Open Source Robotics Foundation, Inc. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the Willow Garage nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include +#include + +#include "gtest/gtest.h" + +#include "rclcpp/rclcpp.hpp" +#include "rclcpp_lifecycle/lifecycle_node.hpp" + +#include "image_transport/image_transport.hpp" +#include "sensor_msgs/msg/image.hpp" + +#include "utils.hpp" + +using namespace std::chrono_literals; + +int total_images_received = 0; + +class MessagePassingTestingLifecycle : public ::testing::Test +{ +public: + sensor_msgs::msg::Image::UniquePtr generate_random_image() + { + auto image = std::make_unique(); + return image; + } + +protected: + void SetUp() + { + node_ = rclcpp_lifecycle::LifecycleNode::make_shared("test_message_passing_lifecycle"); + total_images_received = 0; + } + + rclcpp_lifecycle::LifecycleNode::SharedPtr node_; +}; + + +void imageCallback(const sensor_msgs::msg::Image::ConstSharedPtr & msg) +{ + (void) msg; + total_images_received++; +} + +TEST_F(MessagePassingTestingLifecycle, one_message_passing) +{ + const size_t max_retries = 3; + const size_t max_loops = 200; + const std::chrono::milliseconds sleep_per_loop = std::chrono::milliseconds(10); + + rclcpp::executors::SingleThreadedExecutor executor; + + auto pub = image_transport::create_publisher(node_, "camera/image"); + auto sub = + image_transport::create_subscription(node_, "camera/image", imageCallback, "raw"); + + test_rclcpp::wait_for_subscriber(node_->get_node_graph_interface(), sub.getTopic()); + + ASSERT_EQ(0, total_images_received); + ASSERT_EQ(1u, pub.getNumSubscribers()); + ASSERT_EQ(1u, sub.getNumPublishers()); + + executor.spin_node_some(node_->get_node_base_interface()); + ASSERT_EQ(0, total_images_received); + + size_t retry = 0; + while (retry < max_retries && total_images_received == 0) { + // generate random image and publish it + pub.publish(generate_random_image()); + + executor.spin_node_some(node_->get_node_base_interface()); + size_t loop = 0; + while ((total_images_received != 1) && (loop++ < max_loops)) { + std::this_thread::sleep_for(sleep_per_loop); + executor.spin_node_some(node_->get_node_base_interface()); + } + } + + ASSERT_EQ(1, total_images_received); +} + +TEST_F(MessagePassingTestingLifecycle, one_camera_message_passing) +{ + const size_t max_retries = 3; + const size_t max_loops = 200; + const std::chrono::milliseconds sleep_per_loop = std::chrono::milliseconds(10); + + rclcpp::executors::SingleThreadedExecutor executor; + + auto pub = image_transport::create_camera_publisher(node_, "camera/image"); + auto sub = image_transport::create_camera_subscription( + node_, "camera/image", + [](const sensor_msgs::msg::Image::ConstSharedPtr & image, + const sensor_msgs::msg::CameraInfo::ConstSharedPtr & info) { + (void) image; + (void) info; + total_images_received++; + }, + "raw" + ); + + test_rclcpp::wait_for_subscriber(node_->get_node_graph_interface(), sub.getTopic()); + + ASSERT_EQ(0, total_images_received); + executor.spin_node_some(node_->get_node_base_interface()); + ASSERT_EQ(0, total_images_received); + + size_t retry = 0; + while (retry < max_retries && total_images_received == 0) { + // generate random image and publish it + pub.publish(*generate_random_image().get(), sensor_msgs::msg::CameraInfo()); + + executor.spin_node_some(node_->get_node_base_interface()); + size_t loop = 0; + while ((total_images_received != 1) && (loop++ < max_loops)) { + std::this_thread::sleep_for(sleep_per_loop); + executor.spin_node_some(node_->get_node_base_interface()); + } + } + + ASSERT_EQ(1, total_images_received); +} + +/* +TEST_F(MessagePassingTestingLifecycle, stress_message_passing) +{ + rclcpp::executors::SingleThreadedExecutor executor; + executor.add_node(node_); + + int images_to_stress = 1000; + + image_transport::Publisher pub = it().advertise("camera/image"); + image_transport::Subscriber sub = it().subscribe("camera/image", imageCallback); + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + // generate random image and publish it + int image_pubs = 0; + while (image_pubs < images_to_stress) { + pub.publish(generate_random_image()); + executor.spin_some(); + image_pubs++; + } + + ASSERT_EQ(images_to_stress, total_images_received); +} +*/ + +int main(int argc, char ** argv) +{ + rclcpp::init(argc, argv); + testing::InitGoogleTest(&argc, argv); + int ret = RUN_ALL_TESTS(); + rclcpp::shutdown(); + return ret; +} diff --git a/image_transport/test/test_publisher_lifecycle.cpp b/image_transport/test/test_publisher_lifecycle.cpp new file mode 100644 index 00000000..ab33fe6a --- /dev/null +++ b/image_transport/test/test_publisher_lifecycle.cpp @@ -0,0 +1,99 @@ +// Copyright (c) 2018 Open Source Robotics Foundation, Inc. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the Willow Garage nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include + +#include +#include + +#include "rclcpp/rclcpp.hpp" +#include "rclcpp_lifecycle/lifecycle_node.hpp" + +#include "image_transport/image_transport.hpp" + +class TestPublisherLifecycle : public ::testing::Test +{ +protected: + void SetUp() + { + node_ = rclcpp_lifecycle::LifecycleNode::make_shared("test_publisher_lifecycle"); + } + + rclcpp_lifecycle::LifecycleNode::SharedPtr node_; +}; + +TEST_F(TestPublisherLifecycle, publisher) { + auto pub = image_transport::create_publisher(node_, "camera/image"); + EXPECT_EQ(node_->get_node_graph_interface()->count_publishers("camera/image"), 1u); + pub.shutdown(); + EXPECT_EQ(node_->get_node_graph_interface()->count_publishers("camera/image"), 0u); + // coverage tests: invalid publisher should fail but not crash + pub.publish(sensor_msgs::msg::Image()); + pub.publish(sensor_msgs::msg::Image::ConstSharedPtr()); +} + +TEST_F(TestPublisherLifecycle, image_transport_publisher) { + image_transport::ImageTransport it(node_); + auto pub = it.advertise("camera/image", 1); +} + +TEST_F(TestPublisherLifecycle, camera_publisher) { + auto camera_pub = image_transport::create_camera_publisher(node_, "camera/image"); + EXPECT_EQ(node_->get_node_graph_interface()->count_publishers("camera/image"), 1u); + EXPECT_EQ(node_->get_node_graph_interface()->count_publishers("camera/camera_info"), 1u); + camera_pub.shutdown(); + EXPECT_EQ(node_->get_node_graph_interface()->count_publishers("camera/image"), 0u); + EXPECT_EQ(node_->get_node_graph_interface()->count_publishers("camera/camera_info"), 0u); + // coverage tests: invalid publisher should fail but not crash + camera_pub.publish(sensor_msgs::msg::Image(), sensor_msgs::msg::CameraInfo()); + camera_pub.publish( + sensor_msgs::msg::Image::ConstSharedPtr(), + sensor_msgs::msg::CameraInfo::ConstSharedPtr()); + sensor_msgs::msg::Image image; + sensor_msgs::msg::CameraInfo info; + camera_pub.publish(image, info, rclcpp::Time()); +} + +TEST_F(TestPublisherLifecycle, image_transport_camera_publisher) { + image_transport::ImageTransport it(node_); + auto pub = it.advertiseCamera("camera/image", 1); +} + +TEST_F(TestPublisherLifecycle, image_transport_camera_publisher_qos) { + image_transport::ImageTransport it(node_); + auto pub = it.advertise("camera/image", rmw_qos_profile_sensor_data); +} + +int main(int argc, char ** argv) +{ + rclcpp::init(argc, argv); + testing::InitGoogleTest(&argc, argv); + int ret = RUN_ALL_TESTS(); + rclcpp::shutdown(); + return ret; +} diff --git a/image_transport/test/test_qos_override_lifecycle.cpp b/image_transport/test/test_qos_override_lifecycle.cpp new file mode 100644 index 00000000..9ed2c0c1 --- /dev/null +++ b/image_transport/test/test_qos_override_lifecycle.cpp @@ -0,0 +1,163 @@ +// Copyright (c) 2022 Open Source Robotics Foundation, Inc. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the Willow Garage nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include + +#include +#include + +#include "rclcpp/rclcpp.hpp" +#include "rclcpp_lifecycle/lifecycle_node.hpp" + +#include "image_transport/image_transport.hpp" + +class TestQosOverrideLifecycle : public ::testing::Test +{ +protected: + void SetUp() + { + pub_node_ = rclcpp_lifecycle::LifecycleNode::make_shared("test_publisher_lifecycle"); + qos_override_pub_node_ = rclcpp_lifecycle::LifecycleNode::make_shared( + "test_qos_override_publisher_lifecycle", rclcpp::NodeOptions().parameter_overrides( + { + rclcpp::Parameter( + "qos_overrides./camera/image.publisher.reliability", "best_effort"), + })); + sub_node_ = rclcpp_lifecycle::LifecycleNode::make_shared("test_subscriber_lifecycle"); + qos_override_sub_node_ = rclcpp_lifecycle::LifecycleNode::make_shared( + "test_qos_override_subscriber_lifecycle", rclcpp::NodeOptions().parameter_overrides( + { + rclcpp::Parameter( + "qos_overrides./camera/image.subscription.reliability", "best_effort"), + })); + } + + rclcpp_lifecycle::LifecycleNode::SharedPtr pub_node_; + rclcpp_lifecycle::LifecycleNode::SharedPtr qos_override_pub_node_; + rclcpp_lifecycle::LifecycleNode::SharedPtr sub_node_; + rclcpp_lifecycle::LifecycleNode::SharedPtr qos_override_sub_node_; +}; + +TEST_F(TestQosOverrideLifecycle, qos_override_publisher_without_options) { + auto pub = + image_transport::create_publisher(pub_node_, "camera/image", rmw_qos_profile_default); + auto endpoint_info_vec = pub_node_->get_publishers_info_by_topic("camera/image"); + EXPECT_EQ(endpoint_info_vec[0].qos_profile().reliability(), rclcpp::ReliabilityPolicy::Reliable); + pub.shutdown(); + + pub = image_transport::create_publisher( + qos_override_pub_node_, "camera/image", rmw_qos_profile_default); + + endpoint_info_vec = qos_override_pub_node_->get_publishers_info_by_topic("camera/image"); + EXPECT_EQ( + endpoint_info_vec[0].qos_profile().reliability(), + rclcpp::ReliabilityPolicy::Reliable); + pub.shutdown(); +} + +TEST_F(TestQosOverrideLifecycle, qos_override_publisher_with_options) { + rclcpp::PublisherOptions options; + options.qos_overriding_options = rclcpp::QosOverridingOptions( + { + rclcpp::QosPolicyKind::Depth, + rclcpp::QosPolicyKind::Durability, + rclcpp::QosPolicyKind::History, + rclcpp::QosPolicyKind::Reliability, + }); + + auto pub = image_transport::create_publisher( + pub_node_, "camera/image", rmw_qos_profile_default, options); + auto endpoint_info_vec = pub_node_->get_publishers_info_by_topic("camera/image"); + EXPECT_EQ(endpoint_info_vec[0].qos_profile().reliability(), rclcpp::ReliabilityPolicy::Reliable); + pub.shutdown(); + + pub = image_transport::create_publisher( + qos_override_pub_node_, "camera/image", rmw_qos_profile_default, options); + + endpoint_info_vec = qos_override_pub_node_->get_publishers_info_by_topic("camera/image"); + EXPECT_EQ( + endpoint_info_vec[0].qos_profile().reliability(), + rclcpp::ReliabilityPolicy::BestEffort); + pub.shutdown(); +} + +TEST_F(TestQosOverrideLifecycle, qos_override_subscriber_without_options) { + std::function fcn = + [](const auto & msg) {(void)msg;}; + + auto sub = image_transport::create_subscription( + sub_node_, "camera/image", fcn, "raw", rmw_qos_profile_default); + auto endpoint_info_vec = sub_node_->get_subscriptions_info_by_topic("camera/image"); + EXPECT_EQ(endpoint_info_vec[0].qos_profile().reliability(), rclcpp::ReliabilityPolicy::Reliable); + sub.shutdown(); + + sub = image_transport::create_subscription( + qos_override_sub_node_, "camera/image", fcn, "raw", rmw_qos_profile_default); + + endpoint_info_vec = qos_override_sub_node_->get_subscriptions_info_by_topic("camera/image"); + EXPECT_EQ( + endpoint_info_vec[0].qos_profile().reliability(), + rclcpp::ReliabilityPolicy::Reliable); +} + +TEST_F(TestQosOverrideLifecycle, qos_override_subscriber_with_options) { + std::function fcn = + [](const auto & msg) {(void)msg;}; + + rclcpp::SubscriptionOptions options; + options.qos_overriding_options = rclcpp::QosOverridingOptions( + { + rclcpp::QosPolicyKind::Depth, + rclcpp::QosPolicyKind::Durability, + rclcpp::QosPolicyKind::History, + rclcpp::QosPolicyKind::Reliability, + }); + + auto sub = image_transport::create_subscription( + sub_node_, "camera/image", fcn, "raw", rmw_qos_profile_default, options); + auto endpoint_info_vec = sub_node_->get_subscriptions_info_by_topic("camera/image"); + EXPECT_EQ(endpoint_info_vec[0].qos_profile().reliability(), rclcpp::ReliabilityPolicy::Reliable); + sub.shutdown(); + + sub = image_transport::create_subscription( + qos_override_sub_node_, "camera/image", fcn, "raw", rmw_qos_profile_default, options); + + endpoint_info_vec = qos_override_sub_node_->get_subscriptions_info_by_topic("camera/image"); + EXPECT_EQ( + endpoint_info_vec[0].qos_profile().reliability(), + rclcpp::ReliabilityPolicy::BestEffort); +} + +int main(int argc, char ** argv) +{ + rclcpp::init(argc, argv); + testing::InitGoogleTest(&argc, argv); + int ret = RUN_ALL_TESTS(); + rclcpp::shutdown(); + return ret; +} diff --git a/image_transport/test/test_remapping.cpp b/image_transport/test/test_remapping.cpp index 7194e1ae..1345af56 100644 --- a/image_transport/test/test_remapping.cpp +++ b/image_transport/test/test_remapping.cpp @@ -85,7 +85,7 @@ TEST_F(TestPublisher, RemappedPublisher) { ASSERT_EQ("/namespace/new_topic", sub.getTopic()); ASSERT_EQ("/namespace/new_topic", pub.getTopic()); - test_rclcpp::wait_for_subscriber(node_, sub.getTopic()); + test_rclcpp::wait_for_subscriber(node_->get_node_graph_interface(), sub.getTopic()); ASSERT_FALSE(received); diff --git a/image_transport/test/test_remapping_lifecycle.cpp b/image_transport/test/test_remapping_lifecycle.cpp new file mode 100644 index 00000000..26829b2a --- /dev/null +++ b/image_transport/test/test_remapping_lifecycle.cpp @@ -0,0 +1,130 @@ +// Copyright (c) 2018 Open Source Robotics Foundation, Inc. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the Willow Garage nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include + +#include +#include +#include +#include + +#include "rclcpp/rclcpp.hpp" +#include "rclcpp_lifecycle/lifecycle_node.hpp" +#include "utils.hpp" + +#include "image_transport/image_transport.hpp" + +class TestPublisherLifecycle : public ::testing::Test +{ +protected: + void SetUp() + { + node_ = rclcpp_lifecycle::LifecycleNode::make_shared("node", "namespace"); + std::vector arguments{ + "--ros-args", "-r", "old_topic:=new_topic" + }; + rclcpp::NodeOptions node_options; + node_options.arguments(arguments); + + node_remap_ = rclcpp_lifecycle::LifecycleNode::make_shared( + "node_remap", + "namespace", + node_options + ); + } + + rclcpp_lifecycle::LifecycleNode::SharedPtr node_; + rclcpp_lifecycle::LifecycleNode::SharedPtr node_remap_; +}; + +TEST_F(TestPublisherLifecycle, RemappedPublisher) { + const size_t max_retries = 3; + const size_t max_loops = 200; + const std::chrono::milliseconds sleep_per_loop = std::chrono::milliseconds(10); + + rclcpp::executors::SingleThreadedExecutor executor; + auto image = std::make_shared(); + + // Subscribe + bool received{false}; + auto sub = image_transport::create_subscription( + node_remap_, "old_topic", + [&received](const sensor_msgs::msg::Image::ConstSharedPtr & msg) { + (void)msg; + received = true; + }, "raw"); + + // Publish + auto pub = image_transport::create_publisher(node_, "new_topic"); + + ASSERT_EQ("/namespace/new_topic", sub.getTopic()); + ASSERT_EQ("/namespace/new_topic", pub.getTopic()); + + test_rclcpp::wait_for_subscriber(node_->get_node_graph_interface(), sub.getTopic()); + + ASSERT_FALSE(received); + + size_t retry = 0; + size_t nSub = 0; + size_t nPub = 0; + while (retry < max_retries && nPub == 0 && nSub == 0) { + nSub = pub.getNumSubscribers(); + nPub = sub.getNumPublishers(); + std::this_thread::sleep_for(sleep_per_loop); + } + + executor.spin_node_some(node_->get_node_base_interface()); + executor.spin_node_some(node_remap_->get_node_base_interface()); + + retry = 0; + while (retry < max_retries && !received) { + // generate random image and publish it + pub.publish(image); + + executor.spin_node_some(node_->get_node_base_interface()); + executor.spin_node_some(node_remap_->get_node_base_interface()); + + size_t loop = 0; + while ((!received) && (loop++ < max_loops)) { + std::this_thread::sleep_for(sleep_per_loop); + executor.spin_node_some(node_->get_node_base_interface()); + executor.spin_node_some(node_remap_->get_node_base_interface()); + } + } + + EXPECT_TRUE(received); +} + +int main(int argc, char ** argv) +{ + rclcpp::init(argc, argv); + testing::InitGoogleTest(&argc, argv); + int ret = RUN_ALL_TESTS(); + rclcpp::shutdown(); + return ret; +} diff --git a/image_transport/test/test_single_subscriber_publisher_lifecycle.cpp b/image_transport/test/test_single_subscriber_publisher_lifecycle.cpp new file mode 100644 index 00000000..5afaefda --- /dev/null +++ b/image_transport/test/test_single_subscriber_publisher_lifecycle.cpp @@ -0,0 +1,88 @@ +// Copyright (c) 2018 Open Source Robotics Foundation, Inc. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the Willow Garage nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include +#include +#include + +#include "gtest/gtest.h" + +#include "rclcpp/rclcpp.hpp" +#include "rclcpp_lifecycle/lifecycle_node.hpp" +#include "sensor_msgs/msg/image.hpp" + +#include "image_transport/single_subscriber_publisher.hpp" + +class TestPublisherLifecycle : public ::testing::Test +{ +protected: + static constexpr const char * caller_id = "node"; + static constexpr const char * topic = "/topic"; + + + static void SetUpTestCase() + { + rclcpp::init(0, nullptr); + } + + void SetUp() + { + node = std::make_shared("image_transport", "/ns"); + } + + void TearDown() + { + node.reset(); + } + + + rclcpp_lifecycle::LifecycleNode::SharedPtr node; +}; + +TEST_F(TestPublisherLifecycle, construction_and_destruction) { + auto get_num_subscribers = []() -> size_t {return 0;}; + auto publish_fn = [](const sensor_msgs::msg::Image & /*image*/) {}; + + image_transport::SingleSubscriberPublisher ssp(caller_id, topic, + get_num_subscribers, publish_fn); +} + +TEST_F(TestPublisherLifecycle, getNumSubscribers) { + size_t nSub = 0; + + auto get_num_subscribers = [&nSub]() -> size_t {return nSub;}; + auto publish_fn = [](const sensor_msgs::msg::Image & /*image*/) {}; + + image_transport::SingleSubscriberPublisher ssp(caller_id, topic, + get_num_subscribers, publish_fn); + + nSub = 0; + ASSERT_EQ(ssp.getNumSubscribers(), 0u); + nSub = 1; + ASSERT_EQ(ssp.getNumSubscribers(), 1u); +} diff --git a/image_transport/test/test_subscriber_lifecycle.cpp b/image_transport/test/test_subscriber_lifecycle.cpp new file mode 100644 index 00000000..5312bbf4 --- /dev/null +++ b/image_transport/test/test_subscriber_lifecycle.cpp @@ -0,0 +1,219 @@ +// Copyright (c) 2018 Open Source Robotics Foundation, Inc. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the Willow Garage nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +#include + +#include +#include + +#include "rclcpp/rclcpp.hpp" +#include "rclcpp_lifecycle/lifecycle_node.hpp" + +#include "image_transport/image_transport.hpp" + +class TestSubscriberLifecycle : public ::testing::Test +{ +protected: + void SetUp() + { + node_ = rclcpp_lifecycle::LifecycleNode::make_shared("test_subscriber_lifecycle"); + } + + rclcpp_lifecycle::LifecycleNode::SharedPtr node_; +}; + +TEST_F(TestSubscriberLifecycle, construction_and_destruction) { + std::function fcn = + [](const auto & msg) {(void)msg;}; + + auto sub = image_transport::create_subscription(node_, "camera/image", fcn, "raw"); + + rclcpp::executors::SingleThreadedExecutor executor; + executor.spin_node_some(node_->get_node_base_interface()); +} + +TEST_F(TestSubscriberLifecycle, shutdown) { + std::function fcn = + [](const auto & msg) {(void)msg;}; + + auto sub = image_transport::create_subscription(node_, "camera/image", fcn, "raw"); + EXPECT_EQ(node_->get_node_graph_interface()->count_subscribers("camera/image"), 1u); + sub.shutdown(); + EXPECT_EQ(node_->get_node_graph_interface()->count_subscribers("camera/image"), 0u); +} + +TEST_F(TestSubscriberLifecycle, camera_sub_shutdown) { + std::function fcn = + [](const auto & msg, const auto &) {(void)msg;}; + + auto sub = image_transport::create_camera_subscription(node_, "camera/image", fcn, "raw"); + EXPECT_EQ(node_->get_node_graph_interface()->count_subscribers("camera/image"), 1u); + EXPECT_EQ(node_->get_node_graph_interface()->count_subscribers("camera/camera_info"), 1u); + sub.shutdown(); + EXPECT_EQ(node_->get_node_graph_interface()->count_subscribers("camera/image"), 0u); + EXPECT_EQ(node_->get_node_graph_interface()->count_subscribers("camera/camera_info"), 0u); +} + +TEST_F(TestSubscriberLifecycle, callback_groups) { + using namespace std::chrono_literals; + + // Create a publisher node. + auto node_publisher = rclcpp_lifecycle::LifecycleNode::make_shared( + "image_publisher", + rclcpp::NodeOptions()); + image_transport::ImageTransport it_publisher(node_publisher); + image_transport::Publisher pub = it_publisher.advertise("camera/image", 1); + + auto msg = sensor_msgs::msg::Image(); + auto timer = node_publisher->create_wall_timer(100ms, [&]() {pub.publish(msg);}); + + // Create a subscriber to read the images. + std::atomic flag_1 = false; + std::atomic flag_2 = false; + std::function fcn1 = + [&](const auto & msg) { + (void)msg; + flag_1 = true; + std::this_thread::sleep_for(1s); + }; + std::function fcn2 = + [&](const auto & msg) { + (void)msg; + flag_2 = true; + std::this_thread::sleep_for(1s); + }; + + auto cb_group = node_->create_callback_group(rclcpp::CallbackGroupType::Reentrant); + rclcpp::SubscriptionOptions sub_options; + sub_options.callback_group = cb_group; + + image_transport::ImageTransport it(node_); + + auto subscriber_1 = it.subscribe("camera/image", 1, fcn1, nullptr, nullptr, sub_options); + auto subscriber_2 = it.subscribe("camera/image", 1, fcn2, nullptr, nullptr, sub_options); + + rclcpp::executors::MultiThreadedExecutor executor; + executor.add_node(node_->get_node_base_interface()); + executor.add_node(node_publisher->get_node_base_interface()); + // Both callbacks should be executed and the flags should be set. + std::thread executor_thread([&]() {executor.spin();}); + + // The callbacks sleep for 5 seconds and mutually exclusive callbacks should be blocked. + // However, because of the the multithreaded executor and renentrant callback group, + // the flags should be set, as the callbacks should be in different threads. + auto timeout_elapsed = 0.0s; + auto sleep_duration = 0.1s; + auto timeout = 0.5s; + + while (!(flag_1 && flag_2)) { + std::this_thread::sleep_for(sleep_duration); + timeout_elapsed += sleep_duration; + } + executor.cancel(); + executor_thread.join(); + + EXPECT_LT(timeout_elapsed, timeout); +} + +TEST_F(TestSubscriberLifecycle, callback_groups_custom_qos) { + using namespace std::chrono_literals; + + // Create a publisher node. + auto node_publisher = rclcpp_lifecycle::LifecycleNode::make_shared( + "image_publisher", + rclcpp::NodeOptions()); + image_transport::ImageTransport it_publisher(node_publisher); + image_transport::Publisher pub = it_publisher.advertise( + "camera/image", + rmw_qos_profile_sensor_data); + + auto msg = sensor_msgs::msg::Image(); + auto timer = node_publisher->create_wall_timer(100ms, [&]() {pub.publish(msg);}); + + // Create a subscriber to read the images. + std::atomic flag_1 = false; + std::atomic flag_2 = false; + std::function fcn1 = + [&](const auto & msg) { + (void)msg; + flag_1 = true; + std::this_thread::sleep_for(1s); + }; + std::function fcn2 = + [&](const auto & msg) { + (void)msg; + flag_2 = true; + std::this_thread::sleep_for(1s); + }; + + auto cb_group = node_->create_callback_group(rclcpp::CallbackGroupType::Reentrant); + rclcpp::SubscriptionOptions sub_options; + sub_options.callback_group = cb_group; + + image_transport::ImageTransport it(node_); + + auto subscriber_1 = it.subscribe( + "camera/image", rmw_qos_profile_sensor_data, fcn1, nullptr, + nullptr, sub_options); + auto subscriber_2 = it.subscribe( + "camera/image", rmw_qos_profile_sensor_data, fcn2, nullptr, + nullptr, sub_options); + + rclcpp::executors::MultiThreadedExecutor executor; + executor.add_node(node_->get_node_base_interface()); + executor.add_node(node_publisher->get_node_base_interface()); + // Both callbacks should be executed and the flags should be set. + std::thread executor_thread([&]() {executor.spin();}); + + // The callbacks sleep for 5 seconds and mutually exclusive callbacks should be blocked. + // However, because of the the multithreaded executor and renentrant callback group, + // the flags should be set, as the callbacks should be in different threads. + auto timeout_elapsed = 0.0s; + auto sleep_duration = 0.1s; + auto timeout = 0.5s; + + while (!(flag_1 && flag_2)) { + std::this_thread::sleep_for(sleep_duration); + timeout_elapsed += sleep_duration; + } + executor.cancel(); + executor_thread.join(); + + EXPECT_LT(timeout_elapsed, timeout); +} + +int main(int argc, char ** argv) +{ + rclcpp::init(argc, argv); + testing::InitGoogleTest(&argc, argv); + int ret = RUN_ALL_TESTS(); + rclcpp::shutdown(); + return ret; +} diff --git a/image_transport/test/utils.hpp b/image_transport/test/utils.hpp index aee9d9cf..2148298f 100644 --- a/image_transport/test/utils.hpp +++ b/image_transport/test/utils.hpp @@ -32,7 +32,7 @@ namespace test_rclcpp // subscribers to be > 0, if false it will wait for the number of // subscribers to be 0 void wait_for_subscriber( - std::shared_ptr node, + std::shared_ptr node, const std::string & topic_name, bool to_be_available = true, std::chrono::milliseconds timeout = std::chrono::milliseconds(1), From 688e5de6fa06206c20122a711f4cdf8c62f445df Mon Sep 17 00:00:00 2001 From: Benjamin-Tan Date: Sun, 21 Apr 2024 22:01:00 +0800 Subject: [PATCH 07/14] Change the implementation to template class NodeType with backward compatibility, according to the PR review. --- image_transport/default_plugins.xml | 26 +- .../image_transport/camera_publisher.hpp | 8 +- .../image_transport/camera_subscriber.hpp | 8 +- .../image_transport/image_transport.hpp | 93 +++--- .../include/image_transport/loader_fwds.hpp | 14 +- .../include/image_transport/publisher.hpp | 11 +- .../image_transport/publisher_plugin.hpp | 44 +-- .../include/image_transport/raw_publisher.hpp | 5 +- .../image_transport/raw_subscriber.hpp | 5 +- .../include/image_transport/republish.hpp | 8 +- .../simple_publisher_plugin.hpp | 35 +-- .../simple_subscriber_plugin.hpp | 35 +-- .../single_subscriber_publisher.hpp | 2 - .../include/image_transport/subscriber.hpp | 9 +- .../image_transport/subscriber_filter.hpp | 13 +- .../image_transport/subscriber_plugin.hpp | 66 +---- .../image_transport/transport_hints.hpp | 9 + image_transport/src/camera_publisher.cpp | 81 ++--- image_transport/src/camera_subscriber.cpp | 114 +++---- image_transport/src/image_transport.cpp | 279 +++++++++++------- image_transport/src/list_transports.cpp | 67 ++++- image_transport/src/manifest.cpp | 6 +- image_transport/src/publisher.cpp | 98 +++--- image_transport/src/republish.cpp | 8 +- image_transport/src/subscriber.cpp | 62 ++-- 25 files changed, 581 insertions(+), 525 deletions(-) diff --git a/image_transport/default_plugins.xml b/image_transport/default_plugins.xml index 70c86767..750da371 100644 --- a/image_transport/default_plugins.xml +++ b/image_transport/default_plugins.xml @@ -1,8 +1,17 @@ + type="image_transport::RawPublisher" + base_class_type="image_transport::PublisherPlugin"> + + This is the default publisher. It publishes the Image as-is on the base topic. + + + + This is the default publisher. It publishes the Image as-is on the base topic. @@ -10,8 +19,17 @@ + type="image_transport::RawSubscriber" + base_class_type="image_transport::SubscriberPlugin"> + + This is the default pass-through subscriber for topics of type sensor_msgs/Image. + + + + This is the default pass-through subscriber for topics of type sensor_msgs/Image. diff --git a/image_transport/include/image_transport/camera_publisher.hpp b/image_transport/include/image_transport/camera_publisher.hpp index 497a9d0c..cac5d532 100644 --- a/image_transport/include/image_transport/camera_publisher.hpp +++ b/image_transport/include/image_transport/camera_publisher.hpp @@ -44,9 +44,6 @@ namespace image_transport { - -class ImageTransport; - /** * \brief Manages advertisements for publishing camera images. * @@ -62,6 +59,7 @@ class ImageTransport; * associated with that handle will stop being called. Once all CameraPublisher for a * given base topic go out of scope the topic (and all subtopics) will be unadvertised. */ +template class CameraPublisher { public: @@ -70,14 +68,14 @@ class CameraPublisher IMAGE_TRANSPORT_PUBLIC CameraPublisher( - rclcpp::Node::SharedPtr node, + NodeType * node, const std::string & base_topic, rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::PublisherOptions = rclcpp::PublisherOptions()); IMAGE_TRANSPORT_PUBLIC CameraPublisher( - rclcpp_lifecycle::LifecycleNode::SharedPtr node, + std::shared_ptr node, const std::string & base_topic, rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::PublisherOptions = rclcpp::PublisherOptions()); diff --git a/image_transport/include/image_transport/camera_subscriber.hpp b/image_transport/include/image_transport/camera_subscriber.hpp index 75ca133d..ec540753 100644 --- a/image_transport/include/image_transport/camera_subscriber.hpp +++ b/image_transport/include/image_transport/camera_subscriber.hpp @@ -43,9 +43,6 @@ namespace image_transport { - -class ImageTransport; - /** * \brief Manages a subscription callback on synchronized Image and CameraInfo topics. * @@ -61,6 +58,7 @@ void callback(const sensor_msgs::msg::Image::ConstSharedPtr&, const sensor_msgs: * associated with that handle will stop being called. Once all CameraSubscriber for a given * topic go out of scope the topic will be unsubscribed. */ +template class CameraSubscriber { public: @@ -72,7 +70,7 @@ class CameraSubscriber IMAGE_TRANSPORT_PUBLIC CameraSubscriber( - rclcpp::Node::SharedPtr node, + NodeType * node, const std::string & base_topic, const Callback & callback, const std::string & transport, @@ -80,7 +78,7 @@ class CameraSubscriber IMAGE_TRANSPORT_PUBLIC CameraSubscriber( - rclcpp_lifecycle::LifecycleNode::SharedPtr node, + std::shared_ptr node, const std::string & base_topic, const Callback & callback, const std::string & transport, diff --git a/image_transport/include/image_transport/image_transport.hpp b/image_transport/include/image_transport/image_transport.hpp index 70b24f63..92df2276 100644 --- a/image_transport/include/image_transport/image_transport.hpp +++ b/image_transport/include/image_transport/image_transport.hpp @@ -49,16 +49,18 @@ namespace image_transport /*! * \brief Advertise an image topic, free function version. */ +template IMAGE_TRANSPORT_PUBLIC -Publisher create_publisher( - rclcpp::Node::SharedPtr node, +Publisher create_publisher( + NodeType * node, const std::string & base_topic, rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::PublisherOptions options = rclcpp::PublisherOptions()); +template IMAGE_TRANSPORT_PUBLIC -Publisher create_publisher( - rclcpp_lifecycle::LifecycleNode::SharedPtr node, +Publisher create_publisher( + std::shared_ptr node, const std::string & base_topic, rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::PublisherOptions options = rclcpp::PublisherOptions()); @@ -66,20 +68,22 @@ Publisher create_publisher( /** * \brief Subscribe to an image topic, free function version. */ +template IMAGE_TRANSPORT_PUBLIC -Subscriber create_subscription( - rclcpp::Node::SharedPtr node, +Subscriber create_subscription( + NodeType * node, const std::string & base_topic, - const Subscriber::Callback & callback, + const typename Subscriber::Callback & callback, const std::string & transport, rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::SubscriptionOptions options = rclcpp::SubscriptionOptions()); +template IMAGE_TRANSPORT_PUBLIC -Subscriber create_subscription( - rclcpp_lifecycle::LifecycleNode::SharedPtr node, +Subscriber create_subscription( + std::shared_ptr node, const std::string & base_topic, - const Subscriber::Callback & callback, + const typename Subscriber::Callback & callback, const std::string & transport, rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::SubscriptionOptions options = rclcpp::SubscriptionOptions()); @@ -87,16 +91,18 @@ Subscriber create_subscription( /*! * \brief Advertise a camera, free function version. */ +template IMAGE_TRANSPORT_PUBLIC -CameraPublisher create_camera_publisher( - rclcpp::Node::SharedPtr node, +CameraPublisher create_camera_publisher( + NodeType * node, const std::string & base_topic, rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::PublisherOptions pub_options = rclcpp::PublisherOptions()); +template IMAGE_TRANSPORT_PUBLIC -CameraPublisher create_camera_publisher( - rclcpp_lifecycle::LifecycleNode::SharedPtr node, +CameraPublisher create_camera_publisher( + std::shared_ptr node, const std::string & base_topic, rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::PublisherOptions pub_options = rclcpp::PublisherOptions()); @@ -104,25 +110,29 @@ CameraPublisher create_camera_publisher( /*! * \brief Subscribe to a camera, free function version. */ +template IMAGE_TRANSPORT_PUBLIC -CameraSubscriber create_camera_subscription( - rclcpp::Node::SharedPtr node, +CameraSubscriber create_camera_subscription( + NodeType * node, const std::string & base_topic, - const CameraSubscriber::Callback & callback, + const typename CameraSubscriber::Callback & callback, const std::string & transport, rmw_qos_profile_t custom_qos = rmw_qos_profile_default); +template IMAGE_TRANSPORT_PUBLIC -CameraSubscriber create_camera_subscription( - rclcpp_lifecycle::LifecycleNode::SharedPtr node, +CameraSubscriber create_camera_subscription( + std::shared_ptr node, const std::string & base_topic, - const CameraSubscriber::Callback & callback, + const typename CameraSubscriber::Callback & callback, const std::string & transport, rmw_qos_profile_t custom_qos = rmw_qos_profile_default); +template IMAGE_TRANSPORT_PUBLIC std::vector getDeclaredTransports(); +template IMAGE_TRANSPORT_PUBLIC std::vector getLoadableTransports(); @@ -133,6 +143,7 @@ std::vector getLoadableTransports(); * subscribe() functions for creating advertisements and subscriptions of image topics. */ +template class ImageTransport { public: @@ -141,10 +152,10 @@ class ImageTransport using CameraInfoConstPtr = sensor_msgs::msg::CameraInfo::ConstSharedPtr; IMAGE_TRANSPORT_PUBLIC - explicit ImageTransport(rclcpp::Node::SharedPtr node); + explicit ImageTransport(NodeType * node); IMAGE_TRANSPORT_PUBLIC - explicit ImageTransport(rclcpp_lifecycle::LifecycleNode::SharedPtr node); + explicit ImageTransport(std::shared_ptr node); IMAGE_TRANSPORT_PUBLIC ~ImageTransport(); @@ -153,13 +164,13 @@ class ImageTransport * \brief Advertise an image topic, simple version. */ IMAGE_TRANSPORT_PUBLIC - Publisher advertise(const std::string & base_topic, uint32_t queue_size, bool latch = false); + Publisher advertise(const std::string & base_topic, uint32_t queue_size, bool latch = false); /*! * \brief Advertise an image topic, simple version. */ IMAGE_TRANSPORT_PUBLIC - Publisher advertise( + Publisher advertise( const std::string & base_topic, rmw_qos_profile_t custom_qos, bool latch = false); @@ -177,9 +188,9 @@ class ImageTransport * \brief Subscribe to an image topic, version for arbitrary std::function object. */ IMAGE_TRANSPORT_PUBLIC - Subscriber subscribe( + Subscriber subscribe( const std::string & base_topic, uint32_t queue_size, - const Subscriber::Callback & callback, + const typename Subscriber::Callback & callback, const VoidPtr & tracked_object = VoidPtr(), const TransportHints * transport_hints = nullptr, const rclcpp::SubscriptionOptions options = rclcpp::SubscriptionOptions()); @@ -188,7 +199,7 @@ class ImageTransport * \brief Subscribe to an image topic, version for bare function. */ IMAGE_TRANSPORT_PUBLIC - Subscriber subscribe( + Subscriber subscribe( const std::string & base_topic, uint32_t queue_size, void (* fp)(const ImageConstPtr &), const TransportHints * transport_hints = nullptr, @@ -204,7 +215,7 @@ class ImageTransport * \brief Subscribe to an image topic, version for class member function with bare pointer. */ template - Subscriber subscribe( + Subscriber subscribe( const std::string & base_topic, uint32_t queue_size, void (T::* fp)(const ImageConstPtr &), T * obj, const TransportHints * transport_hints = nullptr, @@ -219,7 +230,7 @@ class ImageTransport * \brief Subscribe to an image topic, version for class member function with shared_ptr. */ template - Subscriber subscribe( + Subscriber subscribe( const std::string & base_topic, uint32_t queue_size, void (T::* fp)(const ImageConstPtr &), const std::shared_ptr & obj, @@ -235,9 +246,9 @@ class ImageTransport * \brief Subscribe to an image topic, version for arbitrary std::function object and QoS. */ IMAGE_TRANSPORT_PUBLIC - Subscriber subscribe( + Subscriber subscribe( const std::string & base_topic, rmw_qos_profile_t custom_qos, - const Subscriber::Callback & callback, + const typename Subscriber::Callback & callback, const VoidPtr & tracked_object, const TransportHints * transport_hints, const rclcpp::SubscriptionOptions options); @@ -246,7 +257,7 @@ class ImageTransport * \brief Subscribe to an image topic, version for bare function. */ IMAGE_TRANSPORT_PUBLIC - Subscriber subscribe( + Subscriber subscribe( const std::string & base_topic, rmw_qos_profile_t custom_qos, void (* fp)(const ImageConstPtr &), const TransportHints * transport_hints = nullptr, @@ -262,7 +273,7 @@ class ImageTransport * \brief Subscribe to an image topic, version for class member function with bare pointer. */ template - Subscriber subscribe( + Subscriber subscribe( const std::string & base_topic, rmw_qos_profile_t custom_qos, void (T::* fp)(const ImageConstPtr &), T * obj, const TransportHints * transport_hints = nullptr, @@ -277,7 +288,7 @@ class ImageTransport * \brief Subscribe to an image topic, version for class member function with shared_ptr. */ template - Subscriber subscribe( + Subscriber subscribe( const std::string & base_topic, rmw_qos_profile_t custom_qos, void (T::* fp)(const ImageConstPtr &), const std::shared_ptr & obj, @@ -293,7 +304,7 @@ class ImageTransport * \brief Advertise a synchronized camera raw image + info topic pair, simple version. */ IMAGE_TRANSPORT_PUBLIC - CameraPublisher advertiseCamera( + CameraPublisher advertiseCamera( const std::string & base_topic, uint32_t queue_size, bool latch = false); @@ -318,9 +329,9 @@ class ImageTransport * named "camera_info" in the same namespace as the base image topic. */ IMAGE_TRANSPORT_PUBLIC - CameraSubscriber subscribeCamera( + CameraSubscriber subscribeCamera( const std::string & base_topic, uint32_t queue_size, - const CameraSubscriber::Callback & callback, + const typename CameraSubscriber::Callback & callback, const VoidPtr & tracked_object = VoidPtr(), const TransportHints * transport_hints = nullptr); @@ -328,7 +339,7 @@ class ImageTransport * \brief Subscribe to a synchronized image & camera info topic pair, version for bare function. */ IMAGE_TRANSPORT_PUBLIC - CameraSubscriber subscribeCamera( + CameraSubscriber subscribeCamera( const std::string & base_topic, uint32_t queue_size, void (* fp)( const ImageConstPtr &, @@ -336,7 +347,7 @@ class ImageTransport const TransportHints * transport_hints = nullptr) { return subscribeCamera( - base_topic, queue_size, CameraSubscriber::Callback(fp), VoidPtr(), + base_topic, queue_size, typename CameraSubscriber::Callback(fp), VoidPtr(), transport_hints); } @@ -345,7 +356,7 @@ class ImageTransport * function with bare pointer. */ template - CameraSubscriber subscribeCamera( + CameraSubscriber subscribeCamera( const std::string & base_topic, uint32_t queue_size, void (T::* fp)( const ImageConstPtr &, @@ -363,7 +374,7 @@ class ImageTransport * function with shared_ptr. */ template - CameraSubscriber subscribeCamera( + CameraSubscriber subscribeCamera( const std::string & base_topic, uint32_t queue_size, void (T::* fp)( const ImageConstPtr &, diff --git a/image_transport/include/image_transport/loader_fwds.hpp b/image_transport/include/image_transport/loader_fwds.hpp index 5f4cf991..de60b032 100644 --- a/image_transport/include/image_transport/loader_fwds.hpp +++ b/image_transport/include/image_transport/loader_fwds.hpp @@ -42,14 +42,20 @@ class ClassLoader; namespace image_transport { +template class PublisherPlugin; +template class SubscriberPlugin; -typedef pluginlib::ClassLoader PubLoader; -typedef std::shared_ptr PubLoaderPtr; +template +using PubLoader = pluginlib::ClassLoader>; +template +using PubLoaderPtr = std::shared_ptr>; -typedef pluginlib::ClassLoader SubLoader; -typedef std::shared_ptr SubLoaderPtr; +template +using SubLoader = pluginlib::ClassLoader>; +template +using SubLoaderPtr = std::shared_ptr>; } // namespace image_transport #endif // IMAGE_TRANSPORT__LOADER_FWDS_HPP_ diff --git a/image_transport/include/image_transport/publisher.hpp b/image_transport/include/image_transport/publisher.hpp index d1967389..90483d92 100644 --- a/image_transport/include/image_transport/publisher.hpp +++ b/image_transport/include/image_transport/publisher.hpp @@ -63,6 +63,7 @@ namespace image_transport * associated with that handle will stop being called. Once all Publisher for a * given base topic go out of scope the topic (and all subtopics) will be unadvertised. */ +template class Publisher { public: @@ -71,17 +72,17 @@ class Publisher IMAGE_TRANSPORT_PUBLIC Publisher( - rclcpp::Node::SharedPtr nh, + NodeType * nh, const std::string & base_topic, - PubLoaderPtr loader, + PubLoaderPtr loader, rmw_qos_profile_t custom_qos, rclcpp::PublisherOptions options = rclcpp::PublisherOptions()); IMAGE_TRANSPORT_PUBLIC Publisher( - rclcpp_lifecycle::LifecycleNode::SharedPtr nh, + std::shared_ptr nh, const std::string & base_topic, - PubLoaderPtr loader, + PubLoaderPtr loader, rmw_qos_profile_t custom_qos, rclcpp::PublisherOptions options = rclcpp::PublisherOptions()); /*! @@ -132,7 +133,7 @@ class Publisher private: void initialise( const std::string & base_topic, - PubLoaderPtr loader, + PubLoaderPtr loader, rmw_qos_profile_t custom_qos, rclcpp::PublisherOptions options); diff --git a/image_transport/include/image_transport/publisher_plugin.hpp b/image_transport/include/image_transport/publisher_plugin.hpp index 57c78d68..ab0e1041 100644 --- a/image_transport/include/image_transport/publisher_plugin.hpp +++ b/image_transport/include/image_transport/publisher_plugin.hpp @@ -46,6 +46,7 @@ namespace image_transport /** * \brief Base class for plugins to Publisher. */ +template class PublisherPlugin { public: @@ -65,30 +66,26 @@ class PublisherPlugin * \brief Advertise a topic, simple version. */ void advertise( - rclcpp::Node::SharedPtr nh, + NodeType * nh, const std::string & base_topic, rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::PublisherOptions options = rclcpp::PublisherOptions()) { - if (impl_) { - throw std::runtime_error("advertise has been called previously!"); + if (!node_) { + node_.reset(nh); } - impl_ = std::make_unique(); - impl_->node_ = nh; advertise(base_topic, custom_qos, options); } void advertise( - rclcpp_lifecycle::LifecycleNode::SharedPtr nh, + std::shared_ptr nh, const std::string & base_topic, rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::PublisherOptions options = rclcpp::PublisherOptions()) { - if (impl_) { - throw std::runtime_error("advertise has been called previously!"); + if (!node_) { + node_ = nh; } - impl_ = std::make_unique(); - impl_->lifecycle_node_ = nh; advertise(base_topic, custom_qos, options); } @@ -99,24 +96,6 @@ class PublisherPlugin { advertiseImpl(base_topic, custom_qos, options); } - - bool get_node(rclcpp::Node::SharedPtr & node) const - { - if (impl_ && impl_->node_) { - node = impl_->node_; - return true; - } - return false; - } - - bool get_node(rclcpp_lifecycle::LifecycleNode::SharedPtr & node) const - { - if (impl_ && impl_->lifecycle_node_) { - node = impl_->lifecycle_node_; - return true; - } - return false; - } /** * \brief Returns the number of subscribers that are currently connected to * this PublisherPlugin. @@ -185,14 +164,7 @@ class PublisherPlugin rmw_qos_profile_t custom_qos, rclcpp::PublisherOptions options) = 0; -private: - struct Impl - { - rclcpp::Node::SharedPtr node_; - rclcpp_lifecycle::LifecycleNode::SharedPtr lifecycle_node_; - }; - - std::unique_ptr impl_; + std::shared_ptr node_; }; } // namespace image_transport diff --git a/image_transport/include/image_transport/raw_publisher.hpp b/image_transport/include/image_transport/raw_publisher.hpp index e52b26b9..c9d07125 100644 --- a/image_transport/include/image_transport/raw_publisher.hpp +++ b/image_transport/include/image_transport/raw_publisher.hpp @@ -46,7 +46,8 @@ namespace image_transport * messages on the base topic. */ -class RawPublisher : public SimplePublisherPlugin +template +class RawPublisher : public SimplePublisherPlugin { public: virtual ~RawPublisher() {} @@ -57,7 +58,7 @@ class RawPublisher : public SimplePublisherPlugin } protected: - virtual void publish(const sensor_msgs::msg::Image & message, const PublishFn & publish_fn) const + virtual void publish(const sensor_msgs::msg::Image & message, const typename SimplePublisherPlugin::PublishFn & publish_fn) const { publish_fn(message); } diff --git a/image_transport/include/image_transport/raw_subscriber.hpp b/image_transport/include/image_transport/raw_subscriber.hpp index efe66e5b..db677e4d 100644 --- a/image_transport/include/image_transport/raw_subscriber.hpp +++ b/image_transport/include/image_transport/raw_subscriber.hpp @@ -46,7 +46,8 @@ namespace image_transport * RawSubscriber is a simple wrapper for ros::Subscriber which listens for Image messages * and passes them through to the callback. */ -class RawSubscriber : public SimpleSubscriberPlugin +template +class RawSubscriber : public SimpleSubscriberPlugin { public: virtual ~RawSubscriber() {} @@ -59,7 +60,7 @@ class RawSubscriber : public SimpleSubscriberPlugin protected: void internalCallback( const std::shared_ptr & message, - const Callback & user_cb) override + const typename SubscriberPlugin::Callback & user_cb) override { user_cb(message); } diff --git a/image_transport/include/image_transport/republish.hpp b/image_transport/include/image_transport/republish.hpp index 11fb7f43..31577e5b 100644 --- a/image_transport/include/image_transport/republish.hpp +++ b/image_transport/include/image_transport/republish.hpp @@ -52,10 +52,10 @@ class Republisher : public rclcpp::Node rclcpp::TimerBase::SharedPtr timer_; bool initialized_{false}; - image_transport::Subscriber sub; - image_transport::Publisher pub; - pluginlib::UniquePtr instance; - std::shared_ptr> loader; + image_transport::Subscriber sub; + image_transport::Publisher pub; + pluginlib::UniquePtr> instance; + std::shared_ptr>> loader; }; } // namespace image_transport diff --git a/image_transport/include/image_transport/simple_publisher_plugin.hpp b/image_transport/include/image_transport/simple_publisher_plugin.hpp index 9dedbbad..c6ae64b5 100644 --- a/image_transport/include/image_transport/simple_publisher_plugin.hpp +++ b/image_transport/include/image_transport/simple_publisher_plugin.hpp @@ -59,8 +59,8 @@ namespace image_transport * getTopicToAdvertise() controls the name of the internal communication topic. * It defaults to \/\. */ -template -class SimplePublisherPlugin : public PublisherPlugin +template +class SimplePublisherPlugin : public PublisherPlugin { public: virtual ~SimplePublisherPlugin() {} @@ -105,18 +105,9 @@ class SimplePublisherPlugin : public PublisherPlugin { std::string transport_topic = getTopicToAdvertise(base_topic); auto qos = rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(custom_qos), custom_qos); - simple_impl_ = std::make_unique(); - if (get_node(simple_impl_->node_)) { - simple_impl_->logger_ = simple_impl_->node_->get_logger(); - simple_impl_->pub_ = simple_impl_->node_->template create_publisher( - transport_topic, qos, options); - } else if (get_node(simple_impl_->lifecycle_node_)) { - simple_impl_->logger_ = simple_impl_->lifecycle_node_->get_logger(); - simple_impl_->pub_ = simple_impl_->lifecycle_node_->template create_publisher( - transport_topic, qos, options); - } else { - throw std::runtime_error("Not a standard node or lifecycle node!"); - } + simple_impl_ = std::make_unique(PublisherPlugin::node_); + simple_impl_->pub_ = simple_impl_->node_->template create_publisher( + transport_topic, qos, options); RCLCPP_DEBUG(simple_impl_->logger_, "getTopicToAdvertise: %s", transport_topic.c_str()); } @@ -143,19 +134,25 @@ class SimplePublisherPlugin : public PublisherPlugin */ virtual std::string getTopicToAdvertise(const std::string & base_topic) const { - return base_topic + "/" + getTransportName(); + return base_topic + "/" + PublisherPlugin::getTransportName(); } private: struct SimplePublisherPluginImpl { - SimplePublisherPluginImpl() - : logger_(rclcpp::get_logger("simple_publisher_plugin_impl")) + explicit SimplePublisherPluginImpl(NodeType * node) + : node_(node), + logger_(node->get_logger()) + { + } + + explicit SimplePublisherPluginImpl(std::shared_ptr node) + : node_(node), + logger_(node->get_logger()) { } - rclcpp::Node::SharedPtr node_; - rclcpp_lifecycle::LifecycleNode::SharedPtr lifecycle_node_; + std::shared_ptr node_; rclcpp::Logger logger_; typename rclcpp::Publisher::SharedPtr pub_; }; diff --git a/image_transport/include/image_transport/simple_subscriber_plugin.hpp b/image_transport/include/image_transport/simple_subscriber_plugin.hpp index d27ace78..2eb7ece2 100644 --- a/image_transport/include/image_transport/simple_subscriber_plugin.hpp +++ b/image_transport/include/image_transport/simple_subscriber_plugin.hpp @@ -59,8 +59,8 @@ namespace image_transport * getTopicToSubscribe() controls the name of the internal communication topic. It * defaults to \/\. */ -template -class SimpleSubscriberPlugin : public SubscriberPlugin +template +class SimpleSubscriberPlugin : public SubscriberPlugin { public: virtual ~SimpleSubscriberPlugin() {} @@ -96,7 +96,7 @@ class SimpleSubscriberPlugin : public SubscriberPlugin virtual void internalCallback( const typename std::shared_ptr & message, - const Callback & user_cb) = 0; + const typename SubscriberPlugin::Callback & user_cb) = 0; /** * \brief Return the communication topic name for a given base topic. @@ -105,12 +105,12 @@ class SimpleSubscriberPlugin : public SubscriberPlugin */ virtual std::string getTopicToSubscribe(const std::string & base_topic) const { - return base_topic + "/" + getTransportName(); + return base_topic + "/" + SubscriberPlugin::getTransportName(); } void subscribeImpl( const std::string & base_topic, - const Callback & callback, + const typename SubscriberPlugin::Callback & callback, rmw_qos_profile_t custom_qos, rclcpp::SubscriptionOptions options) override { @@ -119,30 +119,17 @@ class SimpleSubscriberPlugin : public SubscriberPlugin // ros::NodeHandle param_nh(transport_hints.getParameterNH(), getTransportName()); // auto qos = rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(custom_qos), custom_qos); - if (get_node(impl_->node_)) { - impl_->sub_ = impl_->node_->template create_subscription( - getTopicToSubscribe(base_topic), qos, - [this, callback](const typename std::shared_ptr msg) { - internalCallback(msg, callback); - }, - options); - } else if (get_node(impl_->lifecycle_node_)) { - impl_->sub_ = impl_->lifecycle_node_->template create_subscription( - getTopicToSubscribe(base_topic), qos, - [this, callback](const typename std::shared_ptr msg) { - internalCallback(msg, callback); - }, - options); - } else { - throw std::runtime_error("Not a standard node or lifecycle node!"); - } + impl_->sub_ = SubscriberPlugin::node_->template create_subscription( + getTopicToSubscribe(base_topic), qos, + [this, callback](const typename std::shared_ptr msg) { + internalCallback(msg, callback); + }, + options); } private: struct Impl { - rclcpp::Node::SharedPtr node_; - rclcpp_lifecycle::LifecycleNode::SharedPtr lifecycle_node_; rclcpp::SubscriptionBase::SharedPtr sub_; }; diff --git a/image_transport/include/image_transport/single_subscriber_publisher.hpp b/image_transport/include/image_transport/single_subscriber_publisher.hpp index e6347db8..f553f9e2 100644 --- a/image_transport/include/image_transport/single_subscriber_publisher.hpp +++ b/image_transport/include/image_transport/single_subscriber_publisher.hpp @@ -80,8 +80,6 @@ class SingleSubscriberPublisher std::string topic_; GetNumSubscribersFn num_subscribers_fn_; PublishFn publish_fn_; - - friend class Publisher; // to get publish_fn_ directly }; typedef std::function SubscriberStatusCallback; diff --git a/image_transport/include/image_transport/subscriber.hpp b/image_transport/include/image_transport/subscriber.hpp index 1d6bad23..a32df9d0 100644 --- a/image_transport/include/image_transport/subscriber.hpp +++ b/image_transport/include/image_transport/subscriber.hpp @@ -59,6 +59,7 @@ namespace image_transport * associated with that handle will stop being called. Once all Subscriber for a given * topic go out of scope the topic will be unsubscribed. */ +template class Subscriber { public: @@ -69,20 +70,20 @@ class Subscriber IMAGE_TRANSPORT_PUBLIC Subscriber( - rclcpp::Node::SharedPtr node, + NodeType * node, const std::string & base_topic, const Callback & callback, - SubLoaderPtr loader, + SubLoaderPtr loader, const std::string & transport, rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::SubscriptionOptions options = rclcpp::SubscriptionOptions()); IMAGE_TRANSPORT_PUBLIC Subscriber( - rclcpp_lifecycle::LifecycleNode::SharedPtr node, + std::shared_ptr node, const std::string & base_topic, const Callback & callback, - SubLoaderPtr loader, + SubLoaderPtr loader, const std::string & transport, rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::SubscriptionOptions options = rclcpp::SubscriptionOptions()); diff --git a/image_transport/include/image_transport/subscriber_filter.hpp b/image_transport/include/image_transport/subscriber_filter.hpp index 0050df43..b7b731d6 100644 --- a/image_transport/include/image_transport/subscriber_filter.hpp +++ b/image_transport/include/image_transport/subscriber_filter.hpp @@ -62,6 +62,7 @@ void callback(const std::shared_ptr&); \endverbatim */ +template class SubscriberFilter : public message_filters::SimpleFilter { public: @@ -77,7 +78,7 @@ class SubscriberFilter : public message_filters::SimpleFilter node, const std::string & base_topic, const std::string & transport) { subscribe(node, base_topic, transport); @@ -115,7 +116,7 @@ class SubscriberFilter : public message_filters::SimpleFilter node, const std::string & base_topic, const std::string & transport, rmw_qos_profile_t custom_qos = rmw_qos_profile_default, @@ -180,7 +181,7 @@ class SubscriberFilter : public message_filters::SimpleFilter & getSubscriber() const { return sub_; } @@ -191,7 +192,7 @@ class SubscriberFilter : public message_filters::SimpleFilter sub_; }; } // namespace image_transport diff --git a/image_transport/include/image_transport/subscriber_plugin.hpp b/image_transport/include/image_transport/subscriber_plugin.hpp index 71b18fdd..4f0b2836 100644 --- a/image_transport/include/image_transport/subscriber_plugin.hpp +++ b/image_transport/include/image_transport/subscriber_plugin.hpp @@ -45,6 +45,7 @@ namespace image_transport /** * \brief Base class for plugins to Subscriber. */ +template class IMAGE_TRANSPORT_PUBLIC SubscriberPlugin { public: @@ -66,40 +67,26 @@ class IMAGE_TRANSPORT_PUBLIC SubscriberPlugin * \brief Subscribe to an image topic, version for arbitrary std::function object. */ void subscribe( - rclcpp::Node::SharedPtr node, const std::string & base_topic, + NodeType * node, const std::string & base_topic, const Callback & callback, rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::SubscriptionOptions options = rclcpp::SubscriptionOptions()) { - if (!impl_) { - impl_ = std::make_unique(); + if (!node_) { + node_.reset(node); } - if (impl_->lifecycle_node_) { - throw std::runtime_error("subscribe has been called previously with a lifecycle node!"); - } - if (!impl_->node_) { - impl_->node_ = node; - } - return subscribeImpl(base_topic, callback, custom_qos, options); } void subscribe( - rclcpp_lifecycle::LifecycleNode::SharedPtr node, const std::string & base_topic, + std::shared_ptr node, const std::string & base_topic, const Callback & callback, rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::SubscriptionOptions options = rclcpp::SubscriptionOptions()) { - if (!impl_) { - impl_ = std::make_unique(); - } - if (impl_->node_) { - throw std::runtime_error("subscribe has been called previously with a standard node!"); + if (!node_) { + node_ = node; } - if (!impl_->lifecycle_node_) { - impl_->lifecycle_node_ = node; - } - return subscribeImpl(base_topic, callback, custom_qos, options); } @@ -107,7 +94,7 @@ class IMAGE_TRANSPORT_PUBLIC SubscriberPlugin * \brief Subscribe to an image topic, version for bare function. */ void subscribe( - rclcpp::Node::SharedPtr node, const std::string & base_topic, + NodeType * node, const std::string & base_topic, void (* fp)(const sensor_msgs::msg::Image::ConstSharedPtr &), rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::SubscriptionOptions options = rclcpp::SubscriptionOptions()) @@ -119,7 +106,7 @@ class IMAGE_TRANSPORT_PUBLIC SubscriberPlugin } void subscribe( - rclcpp_lifecycle::LifecycleNode::SharedPtr node, const std::string & base_topic, + std::shared_ptr node, const std::string & base_topic, void (* fp)(const sensor_msgs::msg::Image::ConstSharedPtr &), rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::SubscriptionOptions options = rclcpp::SubscriptionOptions()) @@ -135,7 +122,7 @@ class IMAGE_TRANSPORT_PUBLIC SubscriberPlugin */ template void subscribe( - rclcpp::Node::SharedPtr node, const std::string & base_topic, + NodeType * node, const std::string & base_topic, void (T::* fp)(const sensor_msgs::msg::Image::ConstSharedPtr &), T * obj, rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::SubscriptionOptions options = rclcpp::SubscriptionOptions()) @@ -147,7 +134,7 @@ class IMAGE_TRANSPORT_PUBLIC SubscriberPlugin template void subscribe( - rclcpp_lifecycle::LifecycleNode::SharedPtr node, const std::string & base_topic, + std::shared_ptr node, const std::string & base_topic, void (T::* fp)(const sensor_msgs::msg::Image::ConstSharedPtr &), T * obj, rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::SubscriptionOptions options = rclcpp::SubscriptionOptions()) @@ -162,7 +149,7 @@ class IMAGE_TRANSPORT_PUBLIC SubscriberPlugin */ template void subscribe( - rclcpp::Node::SharedPtr node, const std::string & base_topic, + NodeType * node, const std::string & base_topic, void (T::* fp)(const sensor_msgs::msg::Image::ConstSharedPtr &), std::shared_ptr & obj, rmw_qos_profile_t custom_qos = rmw_qos_profile_default) @@ -174,7 +161,7 @@ class IMAGE_TRANSPORT_PUBLIC SubscriberPlugin template void subscribe( - rclcpp_lifecycle::LifecycleNode::SharedPtr node, const std::string & base_topic, + std::shared_ptr node, const std::string & base_topic, void (T::* fp)(const sensor_msgs::msg::Image::ConstSharedPtr &), std::shared_ptr & obj, rmw_qos_profile_t custom_qos = rmw_qos_profile_default) @@ -184,24 +171,6 @@ class IMAGE_TRANSPORT_PUBLIC SubscriberPlugin std::bind(fp, obj, std::placeholders::_1), custom_qos); } - bool get_node(rclcpp::Node::SharedPtr & node) const - { - if (impl_ && impl_->node_) { - node = impl_->node_; - return true; - } - return false; - } - - bool get_node(rclcpp_lifecycle::LifecycleNode::SharedPtr & node) const - { - if (impl_ && impl_->lifecycle_node_) { - node = impl_->lifecycle_node_; - return true; - } - return false; - } - /** * \brief Get the transport-specific communication topic. */ @@ -236,14 +205,7 @@ class IMAGE_TRANSPORT_PUBLIC SubscriberPlugin rmw_qos_profile_t custom_qos, rclcpp::SubscriptionOptions options) = 0; -private: - struct Impl - { - rclcpp::Node::SharedPtr node_; - rclcpp_lifecycle::LifecycleNode::SharedPtr lifecycle_node_; - }; - - std::unique_ptr impl_; + std::shared_ptr node_; }; } // namespace image_transport diff --git a/image_transport/include/image_transport/transport_hints.hpp b/image_transport/include/image_transport/transport_hints.hpp index ed1c2384..049485a4 100644 --- a/image_transport/include/image_transport/transport_hints.hpp +++ b/image_transport/include/image_transport/transport_hints.hpp @@ -58,6 +58,15 @@ class TransportHints * @param default_transport Preferred transport to use * @param parameter_name The name of the transport parameter */ + IMAGE_TRANSPORT_PUBLIC + TransportHints( + const rclcpp::Node * node, + const std::string & default_transport = "raw", + const std::string & parameter_name = "image_transport") + { + node->get_parameter_or(parameter_name, transport_, default_transport); + } + IMAGE_TRANSPORT_PUBLIC TransportHints( const rclcpp::Node::SharedPtr node, diff --git a/image_transport/src/camera_publisher.cpp b/image_transport/src/camera_publisher.cpp index 8859fecb..b1569c96 100644 --- a/image_transport/src/camera_publisher.cpp +++ b/image_transport/src/camera_publisher.cpp @@ -41,17 +41,21 @@ namespace image_transport { -struct CameraPublisher::Impl +template class CameraPublisher; +template class CameraPublisher; + +template +struct CameraPublisher::Impl { - explicit Impl(rclcpp::Node::SharedPtr node) + explicit Impl(NodeType * node) : node_(node), logger_(node->get_logger()), unadvertised_(false) { } - explicit Impl(rclcpp_lifecycle::LifecycleNode::SharedPtr node) - : lifecycle_node_(node), + explicit Impl(std::shared_ptr node) + : node_(node), logger_(node->get_logger()), unadvertised_(false) { @@ -76,16 +80,16 @@ struct CameraPublisher::Impl } } - rclcpp::Node::SharedPtr node_; - rclcpp_lifecycle::LifecycleNode::SharedPtr lifecycle_node_; + std::shared_ptr node_; rclcpp::Logger logger_; - Publisher image_pub_; + Publisher image_pub_; rclcpp::Publisher::SharedPtr info_pub_; bool unadvertised_; }; -CameraPublisher::CameraPublisher( - rclcpp::Node::SharedPtr node, +template +CameraPublisher::CameraPublisher( + NodeType * node, const std::string & base_topic, rmw_qos_profile_t custom_qos, rclcpp::PublisherOptions pub_options) @@ -94,8 +98,9 @@ CameraPublisher::CameraPublisher( initialise(base_topic, custom_qos, pub_options); } -CameraPublisher::CameraPublisher( - rclcpp_lifecycle::LifecycleNode::SharedPtr node, +template +CameraPublisher::CameraPublisher( + std::shared_ptr node, const std::string & base_topic, rmw_qos_profile_t custom_qos, rclcpp::PublisherOptions pub_options) @@ -104,7 +109,8 @@ CameraPublisher::CameraPublisher( initialise(base_topic, custom_qos, pub_options); } -void CameraPublisher::initialise( +template +void CameraPublisher::initialise( const std::string & base_topic, rmw_qos_profile_t custom_qos, rclcpp::PublisherOptions pub_options) @@ -115,32 +121,20 @@ void CameraPublisher::initialise( // Explicitly resolve name here so we compute the correct CameraInfo topic when the // image topic is remapped (#4539). std::string image_topic; - if (impl_->node_) { - image_topic = rclcpp::expand_topic_or_service_name( - base_topic, - impl_->node_->get_name(), impl_->node_->get_namespace()); - } else { - image_topic = rclcpp::expand_topic_or_service_name( - base_topic, - impl_->lifecycle_node_->get_name(), impl_->lifecycle_node_->get_namespace()); - } + image_topic = rclcpp::expand_topic_or_service_name( + base_topic, + impl_->node_->get_name(), impl_->node_->get_namespace()); std::string info_topic = getCameraInfoTopic(image_topic); auto qos = rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(custom_qos), custom_qos); - if (impl_->node_) { - impl_->image_pub_ = image_transport::create_publisher( - impl_->node_, image_topic, custom_qos, pub_options); - impl_->info_pub_ = - impl_->node_->create_publisher(info_topic, qos); - } else { - impl_->image_pub_ = image_transport::create_publisher( - impl_->lifecycle_node_, image_topic, custom_qos, pub_options); - impl_->info_pub_ = - impl_->lifecycle_node_->create_publisher(info_topic, qos); - } + impl_->image_pub_ = image_transport::create_publisher( + impl_->node_, image_topic, custom_qos, pub_options); + impl_->info_pub_ = + impl_->node_->template create_publisher(info_topic, qos); } -size_t CameraPublisher::getNumSubscribers() const +template +size_t CameraPublisher::getNumSubscribers() const { if (impl_ && impl_->isValid()) { return std::max( @@ -150,7 +144,8 @@ size_t CameraPublisher::getNumSubscribers() const return 0; } -std::string CameraPublisher::getTopic() const +template +std::string CameraPublisher::getTopic() const { if (impl_) { return impl_->image_pub_.getTopic(); @@ -158,7 +153,8 @@ std::string CameraPublisher::getTopic() const return std::string(); } -std::string CameraPublisher::getInfoTopic() const +template +std::string CameraPublisher::getInfoTopic() const { if (impl_) { return impl_->info_pub_->get_topic_name(); @@ -166,7 +162,8 @@ std::string CameraPublisher::getInfoTopic() const return std::string(); } -void CameraPublisher::publish( +template +void CameraPublisher::publish( const sensor_msgs::msg::Image & image, const sensor_msgs::msg::CameraInfo & info) const { @@ -183,7 +180,8 @@ void CameraPublisher::publish( impl_->info_pub_->publish(info); } -void CameraPublisher::publish( +template +void CameraPublisher::publish( const sensor_msgs::msg::Image::ConstSharedPtr & image, const sensor_msgs::msg::CameraInfo::ConstSharedPtr & info) const { @@ -200,7 +198,8 @@ void CameraPublisher::publish( impl_->info_pub_->publish(*info); } -void CameraPublisher::publish( +template +void CameraPublisher::publish( sensor_msgs::msg::Image & image, sensor_msgs::msg::CameraInfo & info, rclcpp::Time stamp) const { @@ -219,7 +218,8 @@ void CameraPublisher::publish( impl_->info_pub_->publish(info); } -void CameraPublisher::shutdown() +template +void CameraPublisher::shutdown() { if (impl_) { impl_->shutdown(); @@ -227,7 +227,8 @@ void CameraPublisher::shutdown() } } -CameraPublisher::operator void *() const +template +CameraPublisher::operator void *() const { return (impl_ && impl_->isValid()) ? reinterpret_cast(1) : reinterpret_cast(0); } diff --git a/image_transport/src/camera_subscriber.cpp b/image_transport/src/camera_subscriber.cpp index c0cf3023..740499a8 100644 --- a/image_transport/src/camera_subscriber.cpp +++ b/image_transport/src/camera_subscriber.cpp @@ -45,13 +45,17 @@ inline void increment(int * value) namespace image_transport { -struct CameraSubscriber::Impl +template class CameraSubscriber; +template class CameraSubscriber; + +template +struct CameraSubscriber::Impl { using Image = sensor_msgs::msg::Image; using CameraInfo = sensor_msgs::msg::CameraInfo; using TimeSync = message_filters::TimeSynchronizer; - explicit Impl(rclcpp::Node::SharedPtr node) + explicit Impl(NodeType * node) : node_(node), logger_(node->get_logger()), sync_(10), @@ -60,8 +64,8 @@ struct CameraSubscriber::Impl { } - explicit Impl(rclcpp_lifecycle::LifecycleNode::SharedPtr node) - : lifecycle_node_(node), + explicit Impl(std::shared_ptr node) + : node_(node), logger_(node->get_logger()), sync_(10), unsubscribed_(false), @@ -84,11 +88,7 @@ struct CameraSubscriber::Impl if (!unsubscribed_) { unsubscribed_ = true; image_sub_.unsubscribe(); - if (node_) { - info_sub_.unsubscribe(); - } else { - lifecycle_info_sub_.unsubscribe(); - } + info_sub_.unsubscribe(); } } @@ -97,11 +97,7 @@ struct CameraSubscriber::Impl int threshold = 3 * both_received_; if (image_received_ > threshold || info_received_ > threshold) { std::string info_topic; - if (node_) { - info_topic = info_sub_.getTopic(); - } else { - info_topic = lifecycle_info_sub_.getTopic(); - } + info_topic = info_sub_.getTopic(); RCLCPP_WARN( logger_, "[image_transport] Topics '%s' and '%s' do not appear to be synchronized. " @@ -115,12 +111,10 @@ struct CameraSubscriber::Impl image_received_ = info_received_ = both_received_ = 0; } - rclcpp::Node::SharedPtr node_; - rclcpp_lifecycle::LifecycleNode::SharedPtr lifecycle_node_; + std::shared_ptr node_; rclcpp::Logger logger_; - SubscriberFilter image_sub_; - message_filters::Subscriber info_sub_; - message_filters::Subscriber lifecycle_info_sub_; + SubscriberFilter image_sub_; + typename message_filters::Subscriber info_sub_; TimeSync sync_; bool unsubscribed_; @@ -129,8 +123,9 @@ struct CameraSubscriber::Impl int image_received_, info_received_, both_received_; }; -CameraSubscriber::CameraSubscriber( - rclcpp::Node::SharedPtr node, +template +CameraSubscriber::CameraSubscriber( + NodeType * node, const std::string & base_topic, const Callback & callback, const std::string & transport, @@ -140,8 +135,9 @@ CameraSubscriber::CameraSubscriber( initialise(base_topic, callback, transport, custom_qos); } -CameraSubscriber::CameraSubscriber( - rclcpp_lifecycle::LifecycleNode::SharedPtr node, +template +CameraSubscriber::CameraSubscriber( + std::shared_ptr node, const std::string & base_topic, const Callback & callback, const std::string & transport, @@ -151,7 +147,8 @@ CameraSubscriber::CameraSubscriber( initialise(base_topic, callback, transport, custom_qos); } -void CameraSubscriber::initialise( +template +void CameraSubscriber::initialise( const std::string & base_topic, const Callback & callback, const std::string & transport, @@ -163,28 +160,15 @@ void CameraSubscriber::initialise( // Must explicitly remap the image topic since we then do some string manipulation on it // to figure out the sibling camera_info topic. std::string image_topic; - if (impl_->node_) { - image_topic = rclcpp::expand_topic_or_service_name( - base_topic, - impl_->node_->get_name(), impl_->node_->get_namespace()); - } else { - image_topic = rclcpp::expand_topic_or_service_name( - base_topic, - impl_->lifecycle_node_->get_name(), impl_->lifecycle_node_->get_namespace()); - } + image_topic = rclcpp::expand_topic_or_service_name( + base_topic, + impl_->node_->get_name(), impl_->node_->get_namespace()); std::string info_topic = getCameraInfoTopic(image_topic); - if (impl_->node_) { - impl_->image_sub_.subscribe(impl_->node_, image_topic, transport, custom_qos); - impl_->info_sub_.subscribe(impl_->node_, info_topic, custom_qos); - impl_->sync_.connectInput(impl_->image_sub_, impl_->info_sub_); - impl_->info_sub_.registerCallback(std::bind(increment, &impl_->info_received_)); - } else { - impl_->image_sub_.subscribe(impl_->lifecycle_node_, image_topic, transport, custom_qos); - impl_->lifecycle_info_sub_.subscribe(impl_->lifecycle_node_, info_topic, custom_qos); - impl_->sync_.connectInput(impl_->image_sub_, impl_->lifecycle_info_sub_); - impl_->lifecycle_info_sub_.registerCallback(std::bind(increment, &impl_->info_received_)); - } + impl_->image_sub_.subscribe(impl_->node_, image_topic, transport, custom_qos); + impl_->info_sub_.subscribe(impl_->node_, info_topic, custom_qos); + impl_->sync_.connectInput(impl_->image_sub_, impl_->info_sub_); + impl_->info_sub_.registerCallback(std::bind(increment, &impl_->info_received_)); impl_->sync_.registerCallback(std::bind(callback, std::placeholders::_1, std::placeholders::_2)); @@ -192,44 +176,33 @@ void CameraSubscriber::initialise( impl_->image_sub_.registerCallback(std::bind(increment, &impl_->image_received_)); impl_->sync_.registerCallback(std::bind(increment, &impl_->both_received_)); - if (impl_->node_) { - impl_->check_synced_timer_ = impl_->node_->create_wall_timer( - std::chrono::seconds(1), - std::bind(&Impl::checkImagesSynchronized, impl_.get())); - } else { - impl_->check_synced_timer_ = impl_->lifecycle_node_->create_wall_timer( - std::chrono::seconds(1), - std::bind(&Impl::checkImagesSynchronized, impl_.get())); - } + impl_->check_synced_timer_ = impl_->node_->create_wall_timer( + std::chrono::seconds(1), + std::bind(&Impl::checkImagesSynchronized, impl_.get())); } -std::string CameraSubscriber::getTopic() const +template +std::string CameraSubscriber::getTopic() const { if (impl_) {return impl_->image_sub_.getTopic();} return std::string(); } -std::string CameraSubscriber::getInfoTopic() const +template +std::string CameraSubscriber::getInfoTopic() const { if (impl_) { - if (impl_->node_) { - return impl_->info_sub_.getSubscriber()->get_topic_name(); - } else { - return impl_->lifecycle_info_sub_.getSubscriber()->get_topic_name(); - } + return impl_->info_sub_.getSubscriber()->get_topic_name(); } return std::string(); } -size_t CameraSubscriber::getNumPublishers() const +template +size_t CameraSubscriber::getNumPublishers() const { if (impl_) { size_t info_pub_count; - if (impl_->node_) { - info_pub_count = impl_->info_sub_.getSubscriber()->get_publisher_count(); - } else { - info_pub_count = impl_->lifecycle_info_sub_.getSubscriber()->get_publisher_count(); - } + info_pub_count = impl_->info_sub_.getSubscriber()->get_publisher_count(); return std::max( impl_->image_sub_.getSubscriber().getNumPublishers(), @@ -238,18 +211,21 @@ size_t CameraSubscriber::getNumPublishers() const return 0; } -std::string CameraSubscriber::getTransport() const +template +std::string CameraSubscriber::getTransport() const { if (impl_) {return impl_->image_sub_.getTransport();} return std::string(); } -void CameraSubscriber::shutdown() +template +void CameraSubscriber::shutdown() { if (impl_) {impl_->shutdown();} } -CameraSubscriber::operator void *() const +template +CameraSubscriber::operator void *() const { return (impl_ && impl_->isValid()) ? reinterpret_cast(1) : reinterpret_cast(0); } diff --git a/image_transport/src/image_transport.cpp b/image_transport/src/image_transport.cpp index 5d83eb95..53e5edfe 100644 --- a/image_transport/src/image_transport.cpp +++ b/image_transport/src/image_transport.cpp @@ -42,62 +42,112 @@ namespace image_transport { +template class ImageTransport; +template class ImageTransport; + + struct Impl { - PubLoaderPtr pub_loader_; - SubLoaderPtr sub_loader_; + PubLoaderPtr pub_loader_; + SubLoaderPtr sub_loader_; Impl() - : pub_loader_(std::make_shared("image_transport", "image_transport::PublisherPlugin")), - sub_loader_(std::make_shared("image_transport", "image_transport::SubscriberPlugin")) + : pub_loader_(std::make_shared>("image_transport", "image_transport::PublisherPlugin")), + sub_loader_(std::make_shared>("image_transport", "image_transport::SubscriberPlugin")) { } }; -static Impl * kImpl = new Impl(); +struct ImplLifecycle +{ + PubLoaderPtr pub_loader_; + SubLoaderPtr sub_loader_; + + ImplLifecycle() + : pub_loader_(std::make_shared>("image_transport", "image_transport::PublisherPlugin")), + sub_loader_(std::make_shared>("image_transport", "image_transport::SubscriberPlugin")) + { + } +}; -Publisher create_publisher( - rclcpp::Node::SharedPtr node, +static std::unique_ptr kImpl = std::make_unique(); +static std::unique_ptr kImpl_lifecycle = std::make_unique(); + +template +Publisher create_publisher( + NodeType * node, const std::string & base_topic, rmw_qos_profile_t custom_qos, rclcpp::PublisherOptions options) { - return Publisher(node, base_topic, kImpl->pub_loader_, custom_qos, options); + if constexpr (std::is_same_v) + { + return Publisher(node, base_topic, kImpl->pub_loader_, custom_qos, options); + } + if constexpr (std::is_same_v) + { + return Publisher(node, base_topic, kImpl_lifecycle->pub_loader_, custom_qos, options); + } } -Publisher create_publisher( - rclcpp_lifecycle::LifecycleNode::SharedPtr node, +template +Publisher create_publisher( + std::shared_ptr node, const std::string & base_topic, rmw_qos_profile_t custom_qos, rclcpp::PublisherOptions options) { - return Publisher(node, base_topic, kImpl->pub_loader_, custom_qos, options); + if constexpr (std::is_same_v) + { + return Publisher(node, base_topic, kImpl->pub_loader_, custom_qos, options); + } + if constexpr (std::is_same_v) + { + return Publisher(node, base_topic, kImpl_lifecycle->pub_loader_, custom_qos, options); + } } -Subscriber create_subscription( - rclcpp::Node::SharedPtr node, +template +Subscriber create_subscription( + NodeType * node, const std::string & base_topic, - const Subscriber::Callback & callback, + const typename Subscriber::Callback & callback, const std::string & transport, rmw_qos_profile_t custom_qos, rclcpp::SubscriptionOptions options) { - return Subscriber(node, base_topic, callback, kImpl->sub_loader_, transport, custom_qos, options); + if constexpr (std::is_same_v) + { + return Subscriber(node, base_topic, callback, kImpl->sub_loader_, transport, custom_qos, options); + } + if constexpr (std::is_same_v) + { + return Subscriber(node, base_topic, callback, kImpl_lifecycle->sub_loader_, transport + "_lifecycle", custom_qos, options); + } } -Subscriber create_subscription( - rclcpp_lifecycle::LifecycleNode::SharedPtr node, +template +Subscriber create_subscription( + std::shared_ptr node, const std::string & base_topic, - const Subscriber::Callback & callback, + const typename Subscriber::Callback & callback, const std::string & transport, rmw_qos_profile_t custom_qos, rclcpp::SubscriptionOptions options) { - return Subscriber(node, base_topic, callback, kImpl->sub_loader_, transport, custom_qos, options); + if constexpr (std::is_same_v) + { + return Subscriber(node, base_topic, callback, kImpl->sub_loader_, transport, custom_qos, options); + } + if constexpr (std::is_same_v) + { + return Subscriber(node, base_topic, callback, kImpl_lifecycle->sub_loader_, transport + "_lifecycle", custom_qos, options); + } } -CameraPublisher create_camera_publisher( - rclcpp::Node::SharedPtr node, +template +CameraPublisher create_camera_publisher( + NodeType * node, const std::string & base_topic, rmw_qos_profile_t custom_qos, rclcpp::PublisherOptions pub_options) @@ -105,8 +155,9 @@ CameraPublisher create_camera_publisher( return CameraPublisher(node, base_topic, custom_qos, pub_options); } -CameraPublisher create_camera_publisher( - rclcpp_lifecycle::LifecycleNode::SharedPtr node, +template +CameraPublisher create_camera_publisher( + std::shared_ptr node, const std::string & base_topic, rmw_qos_profile_t custom_qos, rclcpp::PublisherOptions pub_options) @@ -114,29 +165,40 @@ CameraPublisher create_camera_publisher( return CameraPublisher(node, base_topic, custom_qos, pub_options); } -CameraSubscriber create_camera_subscription( - rclcpp::Node::SharedPtr node, +template +CameraSubscriber create_camera_subscription( + NodeType * node, const std::string & base_topic, - const CameraSubscriber::Callback & callback, + const typename CameraSubscriber::Callback & callback, const std::string & transport, rmw_qos_profile_t custom_qos) { return CameraSubscriber(node, base_topic, callback, transport, custom_qos); } -CameraSubscriber create_camera_subscription( - rclcpp_lifecycle::LifecycleNode::SharedPtr node, +template +CameraSubscriber create_camera_subscription( + std::shared_ptr node, const std::string & base_topic, - const CameraSubscriber::Callback & callback, + const typename CameraSubscriber::Callback & callback, const std::string & transport, rmw_qos_profile_t custom_qos) { return CameraSubscriber(node, base_topic, callback, transport, custom_qos); } +template std::vector getDeclaredTransports() { - std::vector transports = kImpl->sub_loader_->getDeclaredClasses(); + std::vector transports; + if constexpr (std::is_same_v) + { + transports = kImpl->sub_loader_->getDeclaredClasses(); + } + if constexpr (std::is_same_v) + { + transports = kImpl_lifecycle->sub_loader_->getDeclaredClasses(); + } // Remove the "_sub" at the end of each class name. for (std::string & transport : transports) { transport = erase_last_copy(transport, "_sub"); @@ -144,17 +206,33 @@ std::vector getDeclaredTransports() return transports; } +template std::vector getLoadableTransports() { std::vector loadableTransports; - - for (const std::string & transportPlugin : kImpl->sub_loader_->getDeclaredClasses() ) { + std::vector transports; + if constexpr (std::is_same_v) + { + transports = kImpl->sub_loader_->getDeclaredClasses(); + } + if constexpr (std::is_same_v) + { + transports = kImpl_lifecycle->sub_loader_->getDeclaredClasses(); + } + for (const std::string & transportPlugin : transports ) { // If the plugin loads without throwing an exception, add its // transport name to the list of valid plugins, otherwise ignore // it. try { - std::shared_ptr sub = - kImpl->sub_loader_->createUniqueInstance(transportPlugin); + std::shared_ptr> sub; + if constexpr (std::is_same_v) + { + sub = kImpl->sub_loader_->createUniqueInstance(transportPlugin); + } + if constexpr (std::is_same_v) + { + sub = kImpl_lifecycle->sub_loader_->createUniqueInstance(transportPlugin); + } // Remove the "_sub" at the end of each class name. loadableTransports.push_back(erase_last_copy(transportPlugin, "_sub")); } catch (const pluginlib::LibraryLoadException & e) { @@ -167,76 +245,76 @@ std::vector getLoadableTransports() return loadableTransports; } -struct ImageTransport::Impl +template +struct ImageTransport::Impl { - rclcpp::Node::SharedPtr node_; - rclcpp_lifecycle::LifecycleNode::SharedPtr lifecycle_node_; + explicit Impl(NodeType * node) + : node_(node) + { + } + + explicit Impl(std::shared_ptr node) + : node_(node) + { + } + + std::shared_ptr node_; }; -ImageTransport::ImageTransport(rclcpp::Node::SharedPtr node) -: impl_(std::make_unique()) +template +ImageTransport::ImageTransport(NodeType * node) +: impl_(std::make_unique::Impl>(node)) { - impl_->node_ = node; } -ImageTransport::ImageTransport(rclcpp_lifecycle::LifecycleNode::SharedPtr node) -: impl_(std::make_unique()) +template +ImageTransport::ImageTransport(std::shared_ptr node) +: impl_(std::make_unique::Impl>(node)) { - impl_->lifecycle_node_ = node; } -ImageTransport::~ImageTransport() = default; +template +ImageTransport::~ImageTransport() = default; -Publisher ImageTransport::advertise(const std::string & base_topic, uint32_t queue_size, bool latch) +template +Publisher ImageTransport::advertise(const std::string & base_topic, uint32_t queue_size, bool latch) { // TODO(ros2) implement when resolved: https://github.com/ros2/ros2/issues/464 (void) latch; rmw_qos_profile_t custom_qos = rmw_qos_profile_default; custom_qos.depth = queue_size; - if (impl_->node_) { - return create_publisher(impl_->node_, base_topic, custom_qos); - } else { - return create_publisher(impl_->lifecycle_node_, base_topic, custom_qos); - } + return create_publisher(impl_->node_, base_topic, custom_qos); } -Publisher ImageTransport::advertise( +template +Publisher ImageTransport::advertise( const std::string & base_topic, rmw_qos_profile_t custom_qos, bool latch) { // TODO(ros2) implement when resolved: https://github.com/ros2/ros2/issues/464 (void) latch; - if (impl_->node_) { - return create_publisher(impl_->node_, base_topic, custom_qos); - } else { - return create_publisher(impl_->lifecycle_node_, base_topic, custom_qos); - } + return create_publisher(impl_->node_, base_topic, custom_qos); } -Subscriber ImageTransport::subscribe( +template +Subscriber ImageTransport::subscribe( const std::string & base_topic, rmw_qos_profile_t custom_qos, - const Subscriber::Callback & callback, + const typename Subscriber::Callback & callback, const VoidPtr & tracked_object, const TransportHints * transport_hints, const rclcpp::SubscriptionOptions options) { (void) tracked_object; - if (impl_->node_) { - return create_subscription( - impl_->node_, base_topic, callback, - getTransportOrDefault(transport_hints), custom_qos, - options); - } else { - return create_subscription( - impl_->lifecycle_node_, base_topic, callback, - getTransportOrDefault(transport_hints), custom_qos, - options); - } + return create_subscription( + impl_->node_, base_topic, callback, + getTransportOrDefault(transport_hints), custom_qos, + options); } -Subscriber ImageTransport::subscribe( +template +Subscriber ImageTransport::subscribe( const std::string & base_topic, uint32_t queue_size, - const Subscriber::Callback & callback, + const typename Subscriber::Callback & callback, const VoidPtr & tracked_object, const TransportHints * transport_hints, const rclcpp::SubscriptionOptions options) @@ -244,20 +322,14 @@ Subscriber ImageTransport::subscribe( (void) tracked_object; rmw_qos_profile_t custom_qos = rmw_qos_profile_default; custom_qos.depth = queue_size; - if (impl_->node_) { - return create_subscription( - impl_->node_, base_topic, callback, - getTransportOrDefault(transport_hints), custom_qos, - options); - } else { - return create_subscription( - impl_->lifecycle_node_, base_topic, callback, - getTransportOrDefault(transport_hints), custom_qos, - options); - } + return create_subscription( + impl_->node_, base_topic, callback, + getTransportOrDefault(transport_hints), custom_qos, + options); } -CameraPublisher ImageTransport::advertiseCamera( +template +CameraPublisher ImageTransport::advertiseCamera( const std::string & base_topic, uint32_t queue_size, bool latch) { @@ -265,54 +337,43 @@ CameraPublisher ImageTransport::advertiseCamera( (void) latch; rmw_qos_profile_t custom_qos = rmw_qos_profile_default; custom_qos.depth = queue_size; - if (impl_->node_) { - return create_camera_publisher(impl_->node_, base_topic, custom_qos); - } else { - return create_camera_publisher(impl_->lifecycle_node_, base_topic, custom_qos); - } + return create_camera_publisher(impl_->node_, base_topic, custom_qos); } -CameraSubscriber ImageTransport::subscribeCamera( +template +CameraSubscriber ImageTransport::subscribeCamera( const std::string & base_topic, uint32_t queue_size, - const CameraSubscriber::Callback & callback, + const typename CameraSubscriber::Callback & callback, const VoidPtr & tracked_object, const TransportHints * transport_hints) { (void) tracked_object; rmw_qos_profile_t custom_qos = rmw_qos_profile_default; custom_qos.depth = queue_size; - if (impl_->node_) { - return create_camera_subscription( - impl_->node_, base_topic, callback, - getTransportOrDefault(transport_hints), custom_qos); - } else { - return create_camera_subscription( - impl_->lifecycle_node_, base_topic, callback, - getTransportOrDefault(transport_hints), custom_qos); - } + return create_camera_subscription( + impl_->node_, base_topic, callback, + getTransportOrDefault(transport_hints), custom_qos); } -std::vector ImageTransport::getDeclaredTransports() const +template +std::vector ImageTransport::getDeclaredTransports() const { return image_transport::getDeclaredTransports(); } -std::vector ImageTransport::getLoadableTransports() const +template +std::vector ImageTransport::getLoadableTransports() const { return image_transport::getLoadableTransports(); } -std::string ImageTransport::getTransportOrDefault(const TransportHints * transport_hints) +template +std::string ImageTransport::getTransportOrDefault(const TransportHints * transport_hints) { std::string ret; if (nullptr == transport_hints) { - if (impl_->node_) { - TransportHints th(impl_->node_); - ret = th.getTransport(); - } else { - TransportHints th(impl_->lifecycle_node_); - ret = th.getTransport(); - } + TransportHints th(impl_->node_); + ret = th.getTransport(); } else { ret = transport_hints->getTransport(); } diff --git a/image_transport/src/list_transports.cpp b/image_transport/src/list_transports.cpp index ac9748ce..63bf59c2 100644 --- a/image_transport/src/list_transports.cpp +++ b/image_transport/src/list_transports.cpp @@ -54,10 +54,14 @@ struct TransportDesc int main(int /*argc*/, char ** /*argv*/) { - pluginlib::ClassLoader pub_loader( - "image_transport", "image_transport::PublisherPlugin"); - pluginlib::ClassLoader sub_loader( - "image_transport", "image_transport::SubscriberPlugin"); + pluginlib::ClassLoader> pub_loader( + "image_transport", "image_transport::PublisherPlugin"); + pluginlib::ClassLoader> pub_loader_lifecycle( + "image_transport", "image_transport::PublisherPlugin"); + pluginlib::ClassLoader> sub_loader( + "image_transport", "image_transport::SubscriberPlugin"); + pluginlib::ClassLoader> sub_loader_lifecycle( + "image_transport", "image_transport::SubscriberPlugin"); typedef std::map StatusMap; StatusMap transports; @@ -75,6 +79,21 @@ int main(int /*argc*/, char ** /*argv*/) } } + StatusMap transports_lifecycle; + for (const std::string & lookup_name : pub_loader_lifecycle.getDeclaredClasses()) { + std::string transport_name = image_transport::erase_last_copy(lookup_name, "_pub"); + transports_lifecycle[transport_name].pub_name = lookup_name; + transports_lifecycle[transport_name].package_name = pub_loader_lifecycle.getClassPackage(lookup_name); + try { + auto pub = pub_loader_lifecycle.createUniqueInstance(lookup_name); + transports_lifecycle[transport_name].pub_status = SUCCESS; + } catch (const pluginlib::LibraryLoadException &) { + transports_lifecycle[transport_name].pub_status = LIB_LOAD_FAILURE; + } catch (const pluginlib::CreateClassException &) { + transports_lifecycle[transport_name].pub_status = CREATE_FAILURE; + } + } + for (const std::string & lookup_name : sub_loader.getDeclaredClasses()) { std::string transport_name = image_transport::erase_last_copy(lookup_name, "_sub"); transports[transport_name].sub_name = lookup_name; @@ -89,6 +108,21 @@ int main(int /*argc*/, char ** /*argv*/) } } + + for (const std::string & lookup_name : sub_loader_lifecycle.getDeclaredClasses()) { + std::string transport_name = image_transport::erase_last_copy(lookup_name, "_sub"); + transports_lifecycle[transport_name].sub_name = lookup_name; + transports_lifecycle[transport_name].package_name = sub_loader_lifecycle.getClassPackage(lookup_name); + try { + auto sub = sub_loader_lifecycle.createUniqueInstance(lookup_name); + transports_lifecycle[transport_name].sub_status = SUCCESS; + } catch (const pluginlib::LibraryLoadException &) { + transports_lifecycle[transport_name].sub_status = LIB_LOAD_FAILURE; + } catch (const pluginlib::CreateClassException &) { + transports_lifecycle[transport_name].sub_status = CREATE_FAILURE; + } + } + printf("Declared transports:\n"); for (const StatusMap::value_type & value : transports) { const TransportDesc & td = value.second; @@ -126,5 +160,30 @@ int main(int /*argc*/, char ** /*argv*/) } } + printf("\nDetails Lifecycle:\n"); + for (const auto & value : transports_lifecycle) { + const TransportDesc & td = value.second; + printf("----------\n"); + printf("\"%s\"\n", value.first.c_str()); + if (td.pub_status == CREATE_FAILURE || td.sub_status == CREATE_FAILURE) { + printf( + "*** Plugins are built, but could not be loaded. The package may need to be rebuilt or may " + "not be compatible with this release of image_common. ***\n"); + } else if (td.pub_status == LIB_LOAD_FAILURE || td.sub_status == LIB_LOAD_FAILURE) { + printf("*** Plugins are not built. ***\n"); + } + printf(" - Provided by package: %s\n", td.package_name.c_str()); + if (td.pub_status == DOES_NOT_EXIST) { + printf(" - No publisher provided\n"); + } else { + printf(" - Publisher: %s\n", pub_loader_lifecycle.getClassDescription(td.pub_name).c_str()); + } + if (td.sub_status == DOES_NOT_EXIST) { + printf(" - No subscriber provided\n"); + } else { + printf(" - Subscriber: %s\n", sub_loader_lifecycle.getClassDescription(td.sub_name).c_str()); + } + } + return 0; } diff --git a/image_transport/src/manifest.cpp b/image_transport/src/manifest.cpp index 0d1d78d6..e4202601 100644 --- a/image_transport/src/manifest.cpp +++ b/image_transport/src/manifest.cpp @@ -31,5 +31,7 @@ #include "image_transport/raw_publisher.hpp" #include "image_transport/raw_subscriber.hpp" -PLUGINLIB_EXPORT_CLASS(image_transport::RawPublisher, image_transport::PublisherPlugin) -PLUGINLIB_EXPORT_CLASS(image_transport::RawSubscriber, image_transport::SubscriberPlugin) +PLUGINLIB_EXPORT_CLASS(image_transport::RawPublisher, image_transport::PublisherPlugin) +PLUGINLIB_EXPORT_CLASS(image_transport::RawPublisher, image_transport::PublisherPlugin) +PLUGINLIB_EXPORT_CLASS(image_transport::RawSubscriber, image_transport::SubscriberPlugin) +PLUGINLIB_EXPORT_CLASS(image_transport::RawSubscriber, image_transport::SubscriberPlugin) diff --git a/image_transport/src/publisher.cpp b/image_transport/src/publisher.cpp index cd214a8e..677bda5a 100644 --- a/image_transport/src/publisher.cpp +++ b/image_transport/src/publisher.cpp @@ -46,17 +46,21 @@ namespace image_transport { -struct Publisher::Impl +template class Publisher; +template class Publisher; + +template +struct Publisher::Impl { - explicit Impl(rclcpp::Node::SharedPtr node) + explicit Impl(NodeType * node) : node_(node), logger_(node->get_logger()), unadvertised_(false) { } - explicit Impl(rclcpp_lifecycle::LifecycleNode::SharedPtr node) - : lifecycle_node_(node), + explicit Impl(std::shared_ptr node) + : node_(node), logger_(node->get_logger()), unadvertised_(false) { @@ -97,36 +101,38 @@ struct Publisher::Impl } } - rclcpp::Node::SharedPtr node_; - rclcpp_lifecycle::LifecycleNode::SharedPtr lifecycle_node_; + std::shared_ptr node_; rclcpp::Logger logger_; std::string base_topic_; - PubLoaderPtr loader_; - std::vector> publishers_; + PubLoaderPtr loader_; + std::vector>> publishers_; bool unadvertised_; }; -Publisher::Publisher( - rclcpp::Node::SharedPtr node, const std::string & base_topic, - PubLoaderPtr loader, rmw_qos_profile_t custom_qos, +template +Publisher::Publisher( + NodeType * node, const std::string & base_topic, + PubLoaderPtr loader, rmw_qos_profile_t custom_qos, rclcpp::PublisherOptions options) : impl_(std::make_shared(node)) { initialise(base_topic, loader, custom_qos, options); } -Publisher::Publisher( - rclcpp_lifecycle::LifecycleNode::SharedPtr node, const std::string & base_topic, - PubLoaderPtr loader, rmw_qos_profile_t custom_qos, +template +Publisher::Publisher( + std::shared_ptr node, const std::string & base_topic, + PubLoaderPtr loader, rmw_qos_profile_t custom_qos, rclcpp::PublisherOptions options) : impl_(std::make_shared(node)) { initialise(base_topic, loader, custom_qos, options); } -void Publisher::initialise( +template +void Publisher::initialise( const std::string & base_topic, - PubLoaderPtr loader, rmw_qos_profile_t custom_qos, + PubLoaderPtr loader, rmw_qos_profile_t custom_qos, rclcpp::PublisherOptions options) { if (!impl_) { @@ -136,15 +142,9 @@ void Publisher::initialise( // properly (#3652). std::string image_topic; size_t ns_len; - if (impl_->node_) { - image_topic = rclcpp::expand_topic_or_service_name( - base_topic, impl_->node_->get_name(), impl_->node_->get_namespace()); - ns_len = impl_->node_->get_effective_namespace().length(); - } else { - image_topic = rclcpp::expand_topic_or_service_name( - base_topic, impl_->lifecycle_node_->get_name(), impl_->lifecycle_node_->get_namespace()); - ns_len = strlen(impl_->lifecycle_node_->get_namespace()); - } + image_topic = rclcpp::expand_topic_or_service_name( + base_topic, impl_->node_->get_name(), impl_->node_->get_namespace()); + ns_len = strlen(impl_->node_->get_namespace()); impl_->base_topic_ = image_topic; impl_->loader_ = loader; @@ -160,28 +160,16 @@ void Publisher::initialise( all_transport_names.emplace_back(erase_last_copy(lookup_name, "_pub")); } try { - if (impl_->node_) { - allowlist_vec = impl_->node_->declare_parameter>( - param_base_name + ".enable_pub_plugins", all_transport_names); - } else { - allowlist_vec = impl_->lifecycle_node_->declare_parameter>( - param_base_name + ".enable_pub_plugins", all_transport_names); - } + allowlist_vec = impl_->node_->template declare_parameter>( + param_base_name + ".enable_pub_plugins", all_transport_names); } catch (const rclcpp::exceptions::ParameterAlreadyDeclaredException &) { RCLCPP_DEBUG_STREAM( impl_->logger_, param_base_name << ".enable_pub_plugins" << " was previously declared" ); - if (impl_->node_) { - allowlist_vec = - impl_->node_->get_parameter( - param_base_name + - ".enable_pub_plugins").get_value>(); - } else { - allowlist_vec = - impl_->lifecycle_node_->get_parameter( - param_base_name + - ".enable_pub_plugins").get_value>(); - } + allowlist_vec = + impl_->node_->get_parameter( + param_base_name + + ".enable_pub_plugins").template get_value>(); } for (size_t i = 0; i < allowlist_vec.size(); ++i) { allowlist.insert(allowlist_vec[i]); @@ -191,11 +179,7 @@ void Publisher::initialise( const auto & lookup_name = transport_name + "_pub"; try { auto pub = loader->createUniqueInstance(lookup_name); - if (impl_->node_) { - pub->advertise(impl_->node_, image_topic, custom_qos, options); - } else { - pub->advertise(impl_->lifecycle_node_, image_topic, custom_qos, options); - } + pub->advertise(impl_->node_, image_topic, custom_qos, options); impl_->publishers_.push_back(std::move(pub)); } catch (const std::runtime_error & e) { RCLCPP_ERROR( @@ -211,19 +195,22 @@ void Publisher::initialise( } } -size_t Publisher::getNumSubscribers() const +template +size_t Publisher::getNumSubscribers() const { if (impl_ && impl_->isValid()) {return impl_->getNumSubscribers();} return 0; } -std::string Publisher::getTopic() const +template +std::string Publisher::getTopic() const { if (impl_) {return impl_->getTopic();} return std::string(); } -void Publisher::publish(const sensor_msgs::msg::Image & message) const +template +void Publisher::publish(const sensor_msgs::msg::Image & message) const { if (!impl_ || !impl_->isValid()) { // TODO(ros2) Switch to RCUTILS_ASSERT when ros2/rcutils#112 is merged @@ -239,7 +226,8 @@ void Publisher::publish(const sensor_msgs::msg::Image & message) const } } -void Publisher::publish(const sensor_msgs::msg::Image::ConstSharedPtr & message) const +template +void Publisher::publish(const sensor_msgs::msg::Image::ConstSharedPtr & message) const { if (!impl_ || !impl_->isValid()) { // TODO(ros2) Switch to RCUTILS_ASSERT when ros2/rcutils#112 is merged @@ -255,7 +243,8 @@ void Publisher::publish(const sensor_msgs::msg::Image::ConstSharedPtr & message) } } -void Publisher::shutdown() +template +void Publisher::shutdown() { if (impl_) { impl_->shutdown(); @@ -263,7 +252,8 @@ void Publisher::shutdown() } } -Publisher::operator void *() const +template +Publisher::operator void *() const { return (impl_ && impl_->isValid()) ? reinterpret_cast(1) : reinterpret_cast(0); } diff --git a/image_transport/src/republish.cpp b/image_transport/src/republish.cpp index cfe5e773..f9d9d569 100644 --- a/image_transport/src/republish.cpp +++ b/image_transport/src/republish.cpp @@ -113,9 +113,9 @@ void Republisher::initialize() rmw_qos_profile_default, pub_options); // Use Publisher::publish as the subscriber callback - typedef void (image_transport::Publisher::* PublishMemFn)( + typedef void (image_transport::Publisher::* PublishMemFn)( const sensor_msgs::msg::Image::ConstSharedPtr &) const; - PublishMemFn pub_mem_fn = &image_transport::Publisher::publish; + PublishMemFn pub_mem_fn = &image_transport::Publisher::publish; rclcpp::SubscriptionOptions sub_options; sub_options.qos_overriding_options = qos_override_options; @@ -126,10 +126,10 @@ void Republisher::initialize() } else { // Use one specific transport for output // Load transport plugin - typedef image_transport::PublisherPlugin Plugin; + typedef image_transport::PublisherPlugin Plugin; loader = std::make_shared>( "image_transport", - "image_transport::PublisherPlugin"); + "image_transport::PublisherPlugin"); std::string lookup_name = Plugin::getLookupName(out_transport); instance = loader->createUniqueInstance(lookup_name); diff --git a/image_transport/src/subscriber.cpp b/image_transport/src/subscriber.cpp index 06886890..79ee9f07 100644 --- a/image_transport/src/subscriber.cpp +++ b/image_transport/src/subscriber.cpp @@ -44,9 +44,13 @@ namespace image_transport { -struct Subscriber::Impl +template class Subscriber; +template class Subscriber; + +template +struct Subscriber::Impl { - Impl(rclcpp::Node::SharedPtr node, SubLoaderPtr loader) + Impl(NodeType * node, SubLoaderPtr loader) : node_(node), logger_(node->get_logger()), loader_(loader), @@ -54,8 +58,8 @@ struct Subscriber::Impl { } - explicit Impl(rclcpp_lifecycle::LifecycleNode::SharedPtr node, SubLoaderPtr loader) - : lifecycle_node_(node), + explicit Impl(std::shared_ptr node, SubLoaderPtr loader) + : node_(node), logger_(node->get_logger()), loader_(loader), unsubscribed_(false) @@ -82,21 +86,21 @@ struct Subscriber::Impl } } - rclcpp::Node::SharedPtr node_; - rclcpp_lifecycle::LifecycleNode::SharedPtr lifecycle_node_; + std::shared_ptr node_; rclcpp::Logger logger_; std::string lookup_name_; - SubLoaderPtr loader_; - std::shared_ptr subscriber_; + SubLoaderPtr loader_; + std::shared_ptr> subscriber_; bool unsubscribed_; // double constructed_; }; -Subscriber::Subscriber( - rclcpp::Node::SharedPtr node, +template +Subscriber::Subscriber( + NodeType * node, const std::string & base_topic, const Callback & callback, - SubLoaderPtr loader, + SubLoaderPtr loader, const std::string & transport, rmw_qos_profile_t custom_qos, rclcpp::SubscriptionOptions options) @@ -105,11 +109,12 @@ Subscriber::Subscriber( initialise(base_topic, callback, transport, custom_qos, options); } -Subscriber::Subscriber( - rclcpp_lifecycle::LifecycleNode::SharedPtr node, +template +Subscriber::Subscriber( + std::shared_ptr node, const std::string & base_topic, const Callback & callback, - SubLoaderPtr loader, + SubLoaderPtr loader, const std::string & transport, rmw_qos_profile_t custom_qos, rclcpp::SubscriptionOptions options) @@ -118,7 +123,8 @@ Subscriber::Subscriber( initialise(base_topic, callback, transport, custom_qos, options); } -void Subscriber::initialise( +template +void Subscriber::initialise( const std::string & base_topic, const Callback & callback, const std::string & transport, @@ -129,7 +135,7 @@ void Subscriber::initialise( throw std::runtime_error("impl is not constructed!"); } // Load the plugin for the chosen transport. - impl_->lookup_name_ = SubscriberPlugin::getLookupName(transport); + impl_->lookup_name_ = SubscriberPlugin::getLookupName(transport); try { impl_->subscriber_ = impl_->loader_->createSharedInstance(impl_->lookup_name_); } catch (pluginlib::PluginlibException & e) { @@ -144,7 +150,7 @@ void Subscriber::initialise( size_t found = clean_topic.rfind('/'); if (found != std::string::npos) { std::string transport = clean_topic.substr(found + 1); - std::string plugin_name = SubscriberPlugin::getLookupName(transport); + std::string plugin_name = SubscriberPlugin::getLookupName(transport); std::vector plugins = impl_->loader_->getDeclaredClasses(); if (std::find(plugins.begin(), plugins.end(), plugin_name) != plugins.end()) { std::string real_base_topic = clean_topic.substr(0, found); @@ -162,38 +168,38 @@ void Subscriber::initialise( // Tell plugin to subscribe. RCLCPP_DEBUG(impl_->logger_, "Subscribing to: %s\n", base_topic.c_str()); - if (impl_->node_) { - impl_->subscriber_->subscribe(impl_->node_, base_topic, callback, custom_qos, options); - } else { - impl_->subscriber_->subscribe( - impl_->lifecycle_node_, base_topic, callback, custom_qos, options); - } + impl_->subscriber_->subscribe(impl_->node_, base_topic, callback, custom_qos, options); } -std::string Subscriber::getTopic() const +template +std::string Subscriber::getTopic() const { if (impl_) {return impl_->subscriber_->getTopic();} return std::string(); } -size_t Subscriber::getNumPublishers() const +template +size_t Subscriber::getNumPublishers() const { if (impl_) {return impl_->subscriber_->getNumPublishers();} return 0; } -std::string Subscriber::getTransport() const +template +std::string Subscriber::getTransport() const { if (impl_) {return impl_->subscriber_->getTransportName();} return std::string(); } -void Subscriber::shutdown() +template +void Subscriber::shutdown() { if (impl_) {impl_->shutdown();} } -Subscriber::operator void *() const +template +Subscriber::operator void *() const { return (impl_ && impl_->isValid()) ? reinterpret_cast(1) : reinterpret_cast(0); } From d58fdf81c3aab81fc4503a07a72a8159e776f645 Mon Sep 17 00:00:00 2001 From: Benjamin-Tan Date: Sun, 21 Apr 2024 22:10:55 +0800 Subject: [PATCH 08/14] Fix formatting, linting error --- image_transport/default_plugins.xml | 16 ++-- .../image_transport/image_transport.hpp | 3 +- .../include/image_transport/raw_publisher.hpp | 5 +- image_transport/src/image_transport.cpp | 80 ++++++++++--------- image_transport/src/list_transports.cpp | 12 ++- image_transport/src/manifest.cpp | 16 +++- 6 files changed, 76 insertions(+), 56 deletions(-) diff --git a/image_transport/default_plugins.xml b/image_transport/default_plugins.xml index 750da371..fb3e1569 100644 --- a/image_transport/default_plugins.xml +++ b/image_transport/default_plugins.xml @@ -1,8 +1,8 @@ + type="image_transport::RawPublisher<rclcpp::Node>" + base_class_type="image_transport::PublisherPlugin<rclcpp::Node>"> This is the default publisher. It publishes the Image as-is on the base topic. @@ -10,8 +10,8 @@ + type="image_transport::RawPublisher<rclcpp_lifecycle::LifecycleNode>" + base_class_type="image_transport::PublisherPlugin<rclcpp_lifecycle::LifecycleNode>"> This is the default publisher. It publishes the Image as-is on the base topic. @@ -19,8 +19,8 @@ + type="image_transport::RawSubscriber<rclcpp::Node>" + base_class_type="image_transport::SubscriberPlugin<rclcpp::Node>"> This is the default pass-through subscriber for topics of type sensor_msgs/Image. @@ -28,8 +28,8 @@ + type="image_transport::RawSubscriber<rclcpp_lifecycle::LifecycleNode>" + base_class_type="image_transport::SubscriberPlugin<rclcpp_lifecycle::LifecycleNode>"> This is the default pass-through subscriber for topics of type sensor_msgs/Image. diff --git a/image_transport/include/image_transport/image_transport.hpp b/image_transport/include/image_transport/image_transport.hpp index 92df2276..5742bbe9 100644 --- a/image_transport/include/image_transport/image_transport.hpp +++ b/image_transport/include/image_transport/image_transport.hpp @@ -164,7 +164,8 @@ class ImageTransport * \brief Advertise an image topic, simple version. */ IMAGE_TRANSPORT_PUBLIC - Publisher advertise(const std::string & base_topic, uint32_t queue_size, bool latch = false); + Publisher advertise( + const std::string & base_topic, uint32_t queue_size, bool latch = false); /*! * \brief Advertise an image topic, simple version. diff --git a/image_transport/include/image_transport/raw_publisher.hpp b/image_transport/include/image_transport/raw_publisher.hpp index c9d07125..854edbda 100644 --- a/image_transport/include/image_transport/raw_publisher.hpp +++ b/image_transport/include/image_transport/raw_publisher.hpp @@ -58,7 +58,10 @@ class RawPublisher : public SimplePublisherPlugin::PublishFn & publish_fn) const + virtual void publish( + const sensor_msgs::msg::Image & message, + const typename SimplePublisherPlugin::PublishFn & publish_fn) const { publish_fn(message); } diff --git a/image_transport/src/image_transport.cpp b/image_transport/src/image_transport.cpp index 53e5edfe..0ca5858b 100644 --- a/image_transport/src/image_transport.cpp +++ b/image_transport/src/image_transport.cpp @@ -52,8 +52,12 @@ struct Impl SubLoaderPtr sub_loader_; Impl() - : pub_loader_(std::make_shared>("image_transport", "image_transport::PublisherPlugin")), - sub_loader_(std::make_shared>("image_transport", "image_transport::SubscriberPlugin")) + : pub_loader_(std::make_shared>( + "image_transport", + "image_transport::PublisherPlugin")), + sub_loader_(std::make_shared>( + "image_transport", + "image_transport::SubscriberPlugin")) { } }; @@ -64,8 +68,12 @@ struct ImplLifecycle SubLoaderPtr sub_loader_; ImplLifecycle() - : pub_loader_(std::make_shared>("image_transport", "image_transport::PublisherPlugin")), - sub_loader_(std::make_shared>("image_transport", "image_transport::SubscriberPlugin")) + : pub_loader_(std::make_shared>( + "image_transport", + "image_transport::PublisherPlugin")), + sub_loader_(std::make_shared>( + "image_transport", + "image_transport::SubscriberPlugin")) { } }; @@ -80,12 +88,10 @@ Publisher create_publisher( rmw_qos_profile_t custom_qos, rclcpp::PublisherOptions options) { - if constexpr (std::is_same_v) - { + if constexpr (std::is_same_v) { return Publisher(node, base_topic, kImpl->pub_loader_, custom_qos, options); } - if constexpr (std::is_same_v) - { + if constexpr (std::is_same_v) { return Publisher(node, base_topic, kImpl_lifecycle->pub_loader_, custom_qos, options); } } @@ -97,12 +103,10 @@ Publisher create_publisher( rmw_qos_profile_t custom_qos, rclcpp::PublisherOptions options) { - if constexpr (std::is_same_v) - { + if constexpr (std::is_same_v) { return Publisher(node, base_topic, kImpl->pub_loader_, custom_qos, options); } - if constexpr (std::is_same_v) - { + if constexpr (std::is_same_v) { return Publisher(node, base_topic, kImpl_lifecycle->pub_loader_, custom_qos, options); } } @@ -116,13 +120,15 @@ Subscriber create_subscription( rmw_qos_profile_t custom_qos, rclcpp::SubscriptionOptions options) { - if constexpr (std::is_same_v) - { - return Subscriber(node, base_topic, callback, kImpl->sub_loader_, transport, custom_qos, options); + if constexpr (std::is_same_v) { + return Subscriber( + node, base_topic, callback, kImpl->sub_loader_, transport, custom_qos, + options); } - if constexpr (std::is_same_v) - { - return Subscriber(node, base_topic, callback, kImpl_lifecycle->sub_loader_, transport + "_lifecycle", custom_qos, options); + if constexpr (std::is_same_v) { + return Subscriber( + node, base_topic, callback, kImpl_lifecycle->sub_loader_, + transport + "_lifecycle", custom_qos, options); } } @@ -135,13 +141,15 @@ Subscriber create_subscription( rmw_qos_profile_t custom_qos, rclcpp::SubscriptionOptions options) { - if constexpr (std::is_same_v) - { - return Subscriber(node, base_topic, callback, kImpl->sub_loader_, transport, custom_qos, options); + if constexpr (std::is_same_v) { + return Subscriber( + node, base_topic, callback, kImpl->sub_loader_, transport, custom_qos, + options); } - if constexpr (std::is_same_v) - { - return Subscriber(node, base_topic, callback, kImpl_lifecycle->sub_loader_, transport + "_lifecycle", custom_qos, options); + if constexpr (std::is_same_v) { + return Subscriber( + node, base_topic, callback, kImpl_lifecycle->sub_loader_, + transport + "_lifecycle", custom_qos, options); } } @@ -191,12 +199,10 @@ template std::vector getDeclaredTransports() { std::vector transports; - if constexpr (std::is_same_v) - { + if constexpr (std::is_same_v) { transports = kImpl->sub_loader_->getDeclaredClasses(); } - if constexpr (std::is_same_v) - { + if constexpr (std::is_same_v) { transports = kImpl_lifecycle->sub_loader_->getDeclaredClasses(); } // Remove the "_sub" at the end of each class name. @@ -211,26 +217,22 @@ std::vector getLoadableTransports() { std::vector loadableTransports; std::vector transports; - if constexpr (std::is_same_v) - { + if constexpr (std::is_same_v) { transports = kImpl->sub_loader_->getDeclaredClasses(); } - if constexpr (std::is_same_v) - { + if constexpr (std::is_same_v) { transports = kImpl_lifecycle->sub_loader_->getDeclaredClasses(); } - for (const std::string & transportPlugin : transports ) { + for (const std::string & transportPlugin : transports) { // If the plugin loads without throwing an exception, add its // transport name to the list of valid plugins, otherwise ignore // it. try { std::shared_ptr> sub; - if constexpr (std::is_same_v) - { + if constexpr (std::is_same_v) { sub = kImpl->sub_loader_->createUniqueInstance(transportPlugin); } - if constexpr (std::is_same_v) - { + if constexpr (std::is_same_v) { sub = kImpl_lifecycle->sub_loader_->createUniqueInstance(transportPlugin); } // Remove the "_sub" at the end of each class name. @@ -277,7 +279,9 @@ template ImageTransport::~ImageTransport() = default; template -Publisher ImageTransport::advertise(const std::string & base_topic, uint32_t queue_size, bool latch) +Publisher ImageTransport::advertise( + const std::string & base_topic, + uint32_t queue_size, bool latch) { // TODO(ros2) implement when resolved: https://github.com/ros2/ros2/issues/464 (void) latch; diff --git a/image_transport/src/list_transports.cpp b/image_transport/src/list_transports.cpp index 63bf59c2..dbcc5580 100644 --- a/image_transport/src/list_transports.cpp +++ b/image_transport/src/list_transports.cpp @@ -56,11 +56,13 @@ int main(int /*argc*/, char ** /*argv*/) { pluginlib::ClassLoader> pub_loader( "image_transport", "image_transport::PublisherPlugin"); - pluginlib::ClassLoader> pub_loader_lifecycle( + pluginlib::ClassLoader> + pub_loader_lifecycle( "image_transport", "image_transport::PublisherPlugin"); pluginlib::ClassLoader> sub_loader( "image_transport", "image_transport::SubscriberPlugin"); - pluginlib::ClassLoader> sub_loader_lifecycle( + pluginlib::ClassLoader> + sub_loader_lifecycle( "image_transport", "image_transport::SubscriberPlugin"); typedef std::map StatusMap; StatusMap transports; @@ -83,7 +85,8 @@ int main(int /*argc*/, char ** /*argv*/) for (const std::string & lookup_name : pub_loader_lifecycle.getDeclaredClasses()) { std::string transport_name = image_transport::erase_last_copy(lookup_name, "_pub"); transports_lifecycle[transport_name].pub_name = lookup_name; - transports_lifecycle[transport_name].package_name = pub_loader_lifecycle.getClassPackage(lookup_name); + transports_lifecycle[transport_name].package_name = pub_loader_lifecycle.getClassPackage( + lookup_name); try { auto pub = pub_loader_lifecycle.createUniqueInstance(lookup_name); transports_lifecycle[transport_name].pub_status = SUCCESS; @@ -112,7 +115,8 @@ int main(int /*argc*/, char ** /*argv*/) for (const std::string & lookup_name : sub_loader_lifecycle.getDeclaredClasses()) { std::string transport_name = image_transport::erase_last_copy(lookup_name, "_sub"); transports_lifecycle[transport_name].sub_name = lookup_name; - transports_lifecycle[transport_name].package_name = sub_loader_lifecycle.getClassPackage(lookup_name); + transports_lifecycle[transport_name].package_name = sub_loader_lifecycle.getClassPackage( + lookup_name); try { auto sub = sub_loader_lifecycle.createUniqueInstance(lookup_name); transports_lifecycle[transport_name].sub_status = SUCCESS; diff --git a/image_transport/src/manifest.cpp b/image_transport/src/manifest.cpp index e4202601..c588c3ec 100644 --- a/image_transport/src/manifest.cpp +++ b/image_transport/src/manifest.cpp @@ -31,7 +31,15 @@ #include "image_transport/raw_publisher.hpp" #include "image_transport/raw_subscriber.hpp" -PLUGINLIB_EXPORT_CLASS(image_transport::RawPublisher, image_transport::PublisherPlugin) -PLUGINLIB_EXPORT_CLASS(image_transport::RawPublisher, image_transport::PublisherPlugin) -PLUGINLIB_EXPORT_CLASS(image_transport::RawSubscriber, image_transport::SubscriberPlugin) -PLUGINLIB_EXPORT_CLASS(image_transport::RawSubscriber, image_transport::SubscriberPlugin) +PLUGINLIB_EXPORT_CLASS( + image_transport::RawPublisher, + image_transport::PublisherPlugin) +PLUGINLIB_EXPORT_CLASS( + image_transport::RawPublisher, + image_transport::PublisherPlugin) +PLUGINLIB_EXPORT_CLASS( + image_transport::RawSubscriber, + image_transport::SubscriberPlugin) +PLUGINLIB_EXPORT_CLASS( + image_transport::RawSubscriber, + image_transport::SubscriberPlugin) From 9bf1b8f481fa30353b1b5b4e4cfe248076cf21a9 Mon Sep 17 00:00:00 2001 From: Benjamin-Tan Date: Sun, 21 Apr 2024 22:15:51 +0800 Subject: [PATCH 09/14] Use raw pointer instead of unique ptr to workaround segfault, similar to the initial implementation --- image_transport/src/image_transport.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/image_transport/src/image_transport.cpp b/image_transport/src/image_transport.cpp index 0ca5858b..cecbf286 100644 --- a/image_transport/src/image_transport.cpp +++ b/image_transport/src/image_transport.cpp @@ -78,8 +78,8 @@ struct ImplLifecycle } }; -static std::unique_ptr kImpl = std::make_unique(); -static std::unique_ptr kImpl_lifecycle = std::make_unique(); +static Impl * kImpl = new Impl(); +static ImplLifecycle * kImpl_lifecycle = new ImplLifecycle(); template Publisher create_publisher( From 13fb1350e435451df95ee2ea1037ffda0746c161 Mon Sep 17 00:00:00 2001 From: Benjamin-Tan Date: Mon, 22 Apr 2024 22:15:17 +0800 Subject: [PATCH 10/14] Fix undefined reference when using clang --- image_transport/src/camera_publisher.cpp | 6 +++--- image_transport/src/camera_subscriber.cpp | 6 +++--- image_transport/src/image_transport.cpp | 7 +++---- image_transport/src/publisher.cpp | 6 +++--- image_transport/src/subscriber.cpp | 6 +++--- 5 files changed, 15 insertions(+), 16 deletions(-) diff --git a/image_transport/src/camera_publisher.cpp b/image_transport/src/camera_publisher.cpp index b1569c96..bc708573 100644 --- a/image_transport/src/camera_publisher.cpp +++ b/image_transport/src/camera_publisher.cpp @@ -41,9 +41,6 @@ namespace image_transport { -template class CameraPublisher; -template class CameraPublisher; - template struct CameraPublisher::Impl { @@ -234,3 +231,6 @@ CameraPublisher::operator void *() const } } // namespace image_transport + +template class image_transport::CameraPublisher; +template class image_transport::CameraPublisher; diff --git a/image_transport/src/camera_subscriber.cpp b/image_transport/src/camera_subscriber.cpp index 740499a8..825bcc89 100644 --- a/image_transport/src/camera_subscriber.cpp +++ b/image_transport/src/camera_subscriber.cpp @@ -45,9 +45,6 @@ inline void increment(int * value) namespace image_transport { -template class CameraSubscriber; -template class CameraSubscriber; - template struct CameraSubscriber::Impl { @@ -231,3 +228,6 @@ CameraSubscriber::operator void *() const } } // namespace image_transport + +template class image_transport::CameraSubscriber; +template class image_transport::CameraSubscriber; diff --git a/image_transport/src/image_transport.cpp b/image_transport/src/image_transport.cpp index cecbf286..e4014eab 100644 --- a/image_transport/src/image_transport.cpp +++ b/image_transport/src/image_transport.cpp @@ -42,10 +42,6 @@ namespace image_transport { -template class ImageTransport; -template class ImageTransport; - - struct Impl { PubLoaderPtr pub_loader_; @@ -385,3 +381,6 @@ std::string ImageTransport::getTransportOrDefault(const TransportHints } } // namespace image_transport + +template class image_transport::ImageTransport; +template class image_transport::ImageTransport; diff --git a/image_transport/src/publisher.cpp b/image_transport/src/publisher.cpp index 677bda5a..f88f9f4c 100644 --- a/image_transport/src/publisher.cpp +++ b/image_transport/src/publisher.cpp @@ -46,9 +46,6 @@ namespace image_transport { -template class Publisher; -template class Publisher; - template struct Publisher::Impl { @@ -259,3 +256,6 @@ Publisher::operator void *() const } } // namespace image_transport + +template class image_transport::Publisher; +template class image_transport::Publisher; diff --git a/image_transport/src/subscriber.cpp b/image_transport/src/subscriber.cpp index 79ee9f07..a8c2298d 100644 --- a/image_transport/src/subscriber.cpp +++ b/image_transport/src/subscriber.cpp @@ -44,9 +44,6 @@ namespace image_transport { -template class Subscriber; -template class Subscriber; - template struct Subscriber::Impl { @@ -205,3 +202,6 @@ Subscriber::operator void *() const } } // namespace image_transport + +template class image_transport::Subscriber; +template class image_transport::Subscriber; From 07b7bc7630b8e5b6e0e763f2b72b3d19af39a772 Mon Sep 17 00:00:00 2001 From: Benjamin Tan Date: Mon, 20 May 2024 21:50:51 +0800 Subject: [PATCH 11/14] Update copyright to 2024 --- image_transport/include/image_transport/visibility_control.hpp | 2 +- image_transport/test/test_camera_common.cpp | 2 +- image_transport/test/test_message_passing.cpp | 2 +- image_transport/test/test_message_passing_lifecycle.cpp | 2 +- image_transport/test/test_publisher.cpp | 2 +- image_transport/test/test_publisher_lifecycle.cpp | 2 +- image_transport/test/test_qos_override.cpp | 2 +- image_transport/test/test_qos_override_lifecycle.cpp | 2 +- image_transport/test/test_remapping.cpp | 2 +- image_transport/test/test_remapping_lifecycle.cpp | 2 +- image_transport/test/test_single_subscriber_publisher.cpp | 2 +- .../test/test_single_subscriber_publisher_lifecycle.cpp | 2 +- image_transport/test/test_subscriber.cpp | 2 +- image_transport/test/test_subscriber_lifecycle.cpp | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/image_transport/include/image_transport/visibility_control.hpp b/image_transport/include/image_transport/visibility_control.hpp index 2f590311..62e23f9f 100644 --- a/image_transport/include/image_transport/visibility_control.hpp +++ b/image_transport/include/image_transport/visibility_control.hpp @@ -1,4 +1,4 @@ -// Copyright 2018 Open Source Robotics Foundation, Inc. +// Copyright 2024 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. diff --git a/image_transport/test/test_camera_common.cpp b/image_transport/test/test_camera_common.cpp index 89f61c2e..e769307e 100644 --- a/image_transport/test/test_camera_common.cpp +++ b/image_transport/test/test_camera_common.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Open Source Robotics Foundation, Inc. +// Copyright (c) 2024 Open Source Robotics Foundation, Inc. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: diff --git a/image_transport/test/test_message_passing.cpp b/image_transport/test/test_message_passing.cpp index e5a0c8de..fbed57d0 100644 --- a/image_transport/test/test_message_passing.cpp +++ b/image_transport/test/test_message_passing.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Open Source Robotics Foundation, Inc. +// Copyright (c) 2024 Open Source Robotics Foundation, Inc. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: diff --git a/image_transport/test/test_message_passing_lifecycle.cpp b/image_transport/test/test_message_passing_lifecycle.cpp index a1f4a888..af29b71f 100644 --- a/image_transport/test/test_message_passing_lifecycle.cpp +++ b/image_transport/test/test_message_passing_lifecycle.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Open Source Robotics Foundation, Inc. +// Copyright (c) 2024 Open Source Robotics Foundation, Inc. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: diff --git a/image_transport/test/test_publisher.cpp b/image_transport/test/test_publisher.cpp index 6cd12454..375c597a 100644 --- a/image_transport/test/test_publisher.cpp +++ b/image_transport/test/test_publisher.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Open Source Robotics Foundation, Inc. +// Copyright (c) 2024 Open Source Robotics Foundation, Inc. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: diff --git a/image_transport/test/test_publisher_lifecycle.cpp b/image_transport/test/test_publisher_lifecycle.cpp index ab33fe6a..68f840df 100644 --- a/image_transport/test/test_publisher_lifecycle.cpp +++ b/image_transport/test/test_publisher_lifecycle.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Open Source Robotics Foundation, Inc. +// Copyright (c) 2024 Open Source Robotics Foundation, Inc. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: diff --git a/image_transport/test/test_qos_override.cpp b/image_transport/test/test_qos_override.cpp index 4f26e6fe..574f57da 100644 --- a/image_transport/test/test_qos_override.cpp +++ b/image_transport/test/test_qos_override.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Open Source Robotics Foundation, Inc. +// Copyright (c) 2024 Open Source Robotics Foundation, Inc. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: diff --git a/image_transport/test/test_qos_override_lifecycle.cpp b/image_transport/test/test_qos_override_lifecycle.cpp index 9ed2c0c1..6413f966 100644 --- a/image_transport/test/test_qos_override_lifecycle.cpp +++ b/image_transport/test/test_qos_override_lifecycle.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Open Source Robotics Foundation, Inc. +// Copyright (c) 2024 Open Source Robotics Foundation, Inc. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: diff --git a/image_transport/test/test_remapping.cpp b/image_transport/test/test_remapping.cpp index 1345af56..b348c2b7 100644 --- a/image_transport/test/test_remapping.cpp +++ b/image_transport/test/test_remapping.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Open Source Robotics Foundation, Inc. +// Copyright (c) 2024 Open Source Robotics Foundation, Inc. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: diff --git a/image_transport/test/test_remapping_lifecycle.cpp b/image_transport/test/test_remapping_lifecycle.cpp index 26829b2a..3b9dc46c 100644 --- a/image_transport/test/test_remapping_lifecycle.cpp +++ b/image_transport/test/test_remapping_lifecycle.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Open Source Robotics Foundation, Inc. +// Copyright (c) 2024 Open Source Robotics Foundation, Inc. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: diff --git a/image_transport/test/test_single_subscriber_publisher.cpp b/image_transport/test/test_single_subscriber_publisher.cpp index f2137d3a..2bebc5df 100644 --- a/image_transport/test/test_single_subscriber_publisher.cpp +++ b/image_transport/test/test_single_subscriber_publisher.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Open Source Robotics Foundation, Inc. +// Copyright (c) 2024 Open Source Robotics Foundation, Inc. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: diff --git a/image_transport/test/test_single_subscriber_publisher_lifecycle.cpp b/image_transport/test/test_single_subscriber_publisher_lifecycle.cpp index 5afaefda..b10c9fe4 100644 --- a/image_transport/test/test_single_subscriber_publisher_lifecycle.cpp +++ b/image_transport/test/test_single_subscriber_publisher_lifecycle.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Open Source Robotics Foundation, Inc. +// Copyright (c) 2024 Open Source Robotics Foundation, Inc. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: diff --git a/image_transport/test/test_subscriber.cpp b/image_transport/test/test_subscriber.cpp index 1e68529f..78b794b5 100644 --- a/image_transport/test/test_subscriber.cpp +++ b/image_transport/test/test_subscriber.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Open Source Robotics Foundation, Inc. +// Copyright (c) 2024 Open Source Robotics Foundation, Inc. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: diff --git a/image_transport/test/test_subscriber_lifecycle.cpp b/image_transport/test/test_subscriber_lifecycle.cpp index 5312bbf4..4eb4ef94 100644 --- a/image_transport/test/test_subscriber_lifecycle.cpp +++ b/image_transport/test/test_subscriber_lifecycle.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018 Open Source Robotics Foundation, Inc. +// Copyright (c) 2024 Open Source Robotics Foundation, Inc. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: From 4c6d4600a5b1248379878744056c96002bbb1eba Mon Sep 17 00:00:00 2001 From: Benjamin Tan Date: Mon, 20 May 2024 21:55:10 +0800 Subject: [PATCH 12/14] Include headers from PR comments --- image_transport/test/test_message_passing.cpp | 1 + image_transport/test/test_message_passing_lifecycle.cpp | 1 + image_transport/test/test_subscriber.cpp | 4 ++++ image_transport/test/test_subscriber_lifecycle.cpp | 4 ++++ 4 files changed, 10 insertions(+) diff --git a/image_transport/test/test_message_passing.cpp b/image_transport/test/test_message_passing.cpp index fbed57d0..2b5f2b76 100644 --- a/image_transport/test/test_message_passing.cpp +++ b/image_transport/test/test_message_passing.cpp @@ -28,6 +28,7 @@ #include #include +#include #include "gtest/gtest.h" diff --git a/image_transport/test/test_message_passing_lifecycle.cpp b/image_transport/test/test_message_passing_lifecycle.cpp index af29b71f..4508cdea 100644 --- a/image_transport/test/test_message_passing_lifecycle.cpp +++ b/image_transport/test/test_message_passing_lifecycle.cpp @@ -28,6 +28,7 @@ #include #include +#include #include "gtest/gtest.h" diff --git a/image_transport/test/test_subscriber.cpp b/image_transport/test/test_subscriber.cpp index 78b794b5..c092b12f 100644 --- a/image_transport/test/test_subscriber.cpp +++ b/image_transport/test/test_subscriber.cpp @@ -30,6 +30,10 @@ #include #include +#include +#include +#include +#include #include "rclcpp/rclcpp.hpp" diff --git a/image_transport/test/test_subscriber_lifecycle.cpp b/image_transport/test/test_subscriber_lifecycle.cpp index 4eb4ef94..38667f7b 100644 --- a/image_transport/test/test_subscriber_lifecycle.cpp +++ b/image_transport/test/test_subscriber_lifecycle.cpp @@ -30,6 +30,10 @@ #include #include +#include +#include +#include +#include #include "rclcpp/rclcpp.hpp" #include "rclcpp_lifecycle/lifecycle_node.hpp" From c00ac8b6da58b4b945dfa32154c182f6c425cf97 Mon Sep 17 00:00:00 2001 From: Benjamin Tan Date: Mon, 20 May 2024 22:02:47 +0800 Subject: [PATCH 13/14] Include headers from PR comments <2> --- image_transport/test/test_message_passing.cpp | 1 + image_transport/test/test_message_passing_lifecycle.cpp | 1 + image_transport/test/test_remapping.cpp | 2 ++ image_transport/test/test_remapping_lifecycle.cpp | 2 ++ image_transport/test/test_single_subscriber_publisher.cpp | 1 + .../test/test_single_subscriber_publisher_lifecycle.cpp | 1 + 6 files changed, 8 insertions(+) diff --git a/image_transport/test/test_message_passing.cpp b/image_transport/test/test_message_passing.cpp index 2b5f2b76..acb51edf 100644 --- a/image_transport/test/test_message_passing.cpp +++ b/image_transport/test/test_message_passing.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include "gtest/gtest.h" diff --git a/image_transport/test/test_message_passing_lifecycle.cpp b/image_transport/test/test_message_passing_lifecycle.cpp index 4508cdea..650c4420 100644 --- a/image_transport/test/test_message_passing_lifecycle.cpp +++ b/image_transport/test/test_message_passing_lifecycle.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include "gtest/gtest.h" diff --git a/image_transport/test/test_remapping.cpp b/image_transport/test/test_remapping.cpp index b348c2b7..4d9f2bfe 100644 --- a/image_transport/test/test_remapping.cpp +++ b/image_transport/test/test_remapping.cpp @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include "rclcpp/rclcpp.hpp" #include "rclcpp/node.hpp" diff --git a/image_transport/test/test_remapping_lifecycle.cpp b/image_transport/test/test_remapping_lifecycle.cpp index 3b9dc46c..33474f39 100644 --- a/image_transport/test/test_remapping_lifecycle.cpp +++ b/image_transport/test/test_remapping_lifecycle.cpp @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include "rclcpp/rclcpp.hpp" #include "rclcpp_lifecycle/lifecycle_node.hpp" diff --git a/image_transport/test/test_single_subscriber_publisher.cpp b/image_transport/test/test_single_subscriber_publisher.cpp index 2bebc5df..72b48fa0 100644 --- a/image_transport/test/test_single_subscriber_publisher.cpp +++ b/image_transport/test/test_single_subscriber_publisher.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include "gtest/gtest.h" diff --git a/image_transport/test/test_single_subscriber_publisher_lifecycle.cpp b/image_transport/test/test_single_subscriber_publisher_lifecycle.cpp index b10c9fe4..1f969177 100644 --- a/image_transport/test/test_single_subscriber_publisher_lifecycle.cpp +++ b/image_transport/test/test_single_subscriber_publisher_lifecycle.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include "gtest/gtest.h" From 9cf7398f4113efaa9debcd2a20541e943ef1488f Mon Sep 17 00:00:00 2001 From: Benjamin Tan Date: Mon, 20 May 2024 22:23:49 +0800 Subject: [PATCH 14/14] Improve implementation to use shared ptr directly --- .../image_transport/publisher_plugin.hpp | 20 +++---------------- .../simple_publisher_plugin.hpp | 3 ++- .../simple_subscriber_plugin.hpp | 3 ++- .../image_transport/subscriber_plugin.hpp | 15 +++++--------- 4 files changed, 12 insertions(+), 29 deletions(-) diff --git a/image_transport/include/image_transport/publisher_plugin.hpp b/image_transport/include/image_transport/publisher_plugin.hpp index ab0e1041..ff64924b 100644 --- a/image_transport/include/image_transport/publisher_plugin.hpp +++ b/image_transport/include/image_transport/publisher_plugin.hpp @@ -71,10 +71,7 @@ class PublisherPlugin rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::PublisherOptions options = rclcpp::PublisherOptions()) { - if (!node_) { - node_.reset(nh); - } - advertise(base_topic, custom_qos, options); + advertiseImpl(std::shared_ptr(nh), base_topic, custom_qos, options); } void advertise( @@ -83,19 +80,9 @@ class PublisherPlugin rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::PublisherOptions options = rclcpp::PublisherOptions()) { - if (!node_) { - node_ = nh; - } - advertise(base_topic, custom_qos, options); + advertiseImpl(nh, base_topic, custom_qos, options); } - void advertise( - const std::string & base_topic, - rmw_qos_profile_t custom_qos = rmw_qos_profile_default, - rclcpp::PublisherOptions options = rclcpp::PublisherOptions()) - { - advertiseImpl(base_topic, custom_qos, options); - } /** * \brief Returns the number of subscribers that are currently connected to * this PublisherPlugin. @@ -160,11 +147,10 @@ class PublisherPlugin * \brief Advertise a topic. Must be implemented by the subclass. */ virtual void advertiseImpl( + std::shared_ptr nh, const std::string & base_topic, rmw_qos_profile_t custom_qos, rclcpp::PublisherOptions options) = 0; - - std::shared_ptr node_; }; } // namespace image_transport diff --git a/image_transport/include/image_transport/simple_publisher_plugin.hpp b/image_transport/include/image_transport/simple_publisher_plugin.hpp index c6ae64b5..da547771 100644 --- a/image_transport/include/image_transport/simple_publisher_plugin.hpp +++ b/image_transport/include/image_transport/simple_publisher_plugin.hpp @@ -99,13 +99,14 @@ class SimplePublisherPlugin : public PublisherPlugin protected: void advertiseImpl( + std::shared_ptr nh, const std::string & base_topic, rmw_qos_profile_t custom_qos, rclcpp::PublisherOptions options) override { std::string transport_topic = getTopicToAdvertise(base_topic); auto qos = rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(custom_qos), custom_qos); - simple_impl_ = std::make_unique(PublisherPlugin::node_); + simple_impl_ = std::make_unique(nh); simple_impl_->pub_ = simple_impl_->node_->template create_publisher( transport_topic, qos, options); diff --git a/image_transport/include/image_transport/simple_subscriber_plugin.hpp b/image_transport/include/image_transport/simple_subscriber_plugin.hpp index 2eb7ece2..991e11e8 100644 --- a/image_transport/include/image_transport/simple_subscriber_plugin.hpp +++ b/image_transport/include/image_transport/simple_subscriber_plugin.hpp @@ -109,6 +109,7 @@ class SimpleSubscriberPlugin : public SubscriberPlugin } void subscribeImpl( + std::shared_ptr node, const std::string & base_topic, const typename SubscriberPlugin::Callback & callback, rmw_qos_profile_t custom_qos, @@ -119,7 +120,7 @@ class SimpleSubscriberPlugin : public SubscriberPlugin // ros::NodeHandle param_nh(transport_hints.getParameterNH(), getTransportName()); // auto qos = rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(custom_qos), custom_qos); - impl_->sub_ = SubscriberPlugin::node_->template create_subscription( + impl_->sub_ = node->template create_subscription( getTopicToSubscribe(base_topic), qos, [this, callback](const typename std::shared_ptr msg) { internalCallback(msg, callback); diff --git a/image_transport/include/image_transport/subscriber_plugin.hpp b/image_transport/include/image_transport/subscriber_plugin.hpp index 4f0b2836..ee9ddf5e 100644 --- a/image_transport/include/image_transport/subscriber_plugin.hpp +++ b/image_transport/include/image_transport/subscriber_plugin.hpp @@ -72,10 +72,9 @@ class IMAGE_TRANSPORT_PUBLIC SubscriberPlugin rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::SubscriptionOptions options = rclcpp::SubscriptionOptions()) { - if (!node_) { - node_.reset(node); - } - return subscribeImpl(base_topic, callback, custom_qos, options); + return subscribeImpl( + std::shared_ptr(node), base_topic, callback, custom_qos, + options); } void subscribe( @@ -84,10 +83,7 @@ class IMAGE_TRANSPORT_PUBLIC SubscriberPlugin rmw_qos_profile_t custom_qos = rmw_qos_profile_default, rclcpp::SubscriptionOptions options = rclcpp::SubscriptionOptions()) { - if (!node_) { - node_ = node; - } - return subscribeImpl(base_topic, callback, custom_qos, options); + return subscribeImpl(node, base_topic, callback, custom_qos, options); } /** @@ -200,12 +196,11 @@ class IMAGE_TRANSPORT_PUBLIC SubscriberPlugin * \brief Subscribe to an image transport topic. Must be implemented by the subclass. */ virtual void subscribeImpl( + std::shared_ptr node, const std::string & base_topic, const Callback & callback, rmw_qos_profile_t custom_qos, rclcpp::SubscriptionOptions options) = 0; - - std::shared_ptr node_; }; } // namespace image_transport